1
0
mirror of https://github.com/kellyjonbrazil/jc.git synced 2025-07-15 01:24:29 +02:00

Merge branch 'dev' into arp_aix

This commit is contained in:
Dave Marquardt
2023-01-06 15:14:39 -06:00
committed by GitHub
20 changed files with 1576 additions and 144 deletions

View File

@ -1,13 +1,14 @@
jc changelog
20230103 v1.22.5
20230105 v1.22.5
- Add TOML parser
- Update copyright dates
- Add AIX support for the `mount` command parser
- Fix `lsusb` parser when extra hub port status information is output
- Refactor `lsusb` parser for more code reuse
- Fix INI parser to include top-level values with no section header
- Fix INI and Key/Value parsers to only remove one quotation mark from the
beginning and end of values.
- Update copyright dates
20221230 v1.22.4
- Add `iwconfig` command parser

View File

@ -11,10 +11,6 @@ Parses standard `INI` files.
- Comment prefix can be `#` or `;`. Comments must be on their own line.
- If duplicate keys are found, only the last value will be used.
> Note: If there is no top-level section identifier, then this parser will
> add a key named `_top_level_section_` with the top-level key/values
> included.
> Note: The section identifier `[DEFAULT]` is special and provides default
> values for the section keys that follow. To disable this behavior you must
> rename the `[DEFAULT]` section identifier to something else before
@ -47,34 +43,28 @@ standard library documentation for more details.
Examples:
$ cat example.ini
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
foo = bar
baz = buz
[bitbucket.org]
User = hg
[section1]
key1 = value1
key2 = value2
[topsecret.server.com]
Port = 50022
ForwardX11 = no
[section2]
key1 = value1
key2 = value2
$ cat example.ini | jc --ini -p
{
"bitbucket.org": {
"ServerAliveInterval": "45",
"Compression": "yes",
"CompressionLevel": "9",
"ForwardX11": "yes",
"User": "hg"
"foo": "bar",
"baz": "buz",
"section1": {
"key1": "value1",
"key2": "value2"
},
"topsecret.server.com": {
"ServerAliveInterval": "45",
"Compression": "yes",
"CompressionLevel": "9",
"ForwardX11": "no",
"Port": "50022"
"section2": {
"key1": "value1",
"key2": "value2"
}
}

81
docs/parsers/toml.md Normal file
View File

@ -0,0 +1,81 @@
[Home](https://kellyjonbrazil.github.io/jc/)
<a id="jc.parsers.toml"></a>
# jc.parsers.toml
jc - JSON Convert TOML file parser
Usage (cli):
$ cat file.toml | jc --toml
Usage (module):
import jc
result = jc.parse('toml', toml_file_output)
Schema:
TOML Document converted to a Dictionary.
See https://toml.io/en/ for details.
{
"key1": string/int/float/boolean/null/array/object,
"key2": string/int/float/boolean/null/array/object
}
Examples:
$ cat file.toml
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00
[database]
enabled = true
ports = [ 8000, 8001, 8002 ]
$ cat file.toml | jc --toml -p
{
"title": "TOML Example",
"owner": {
"name": "Tom Preston-Werner",
"dob": 296667120,
"dob_iso": "1979-05-27T07:32:00-08:00"
},
"database": {
"enabled": true,
"ports": [
8000,
8001,
8002
]
}
}
<a id="jc.parsers.toml.parse"></a>
### parse
```python
def parse(data: str, raw: bool = False, quiet: bool = False) -> JSONDictType
```
Main text parsing function
Parameters:
data: (string) text data to parse
raw: (boolean) unprocessed output if True
quiet: (boolean) suppress warning messages if True
Returns:
Dictionary. Raw or processed structured data.
### Parser Information
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)

View File

@ -18,8 +18,8 @@ Usage (module):
Schema:
YAML Document converted to a Dictionary
See https://pypi.org/project/ruamel.yaml for details
YAML Document converted to a Dictionary.
See https://pypi.org/project/ruamel.yaml for details.
[
{
@ -30,7 +30,7 @@ Schema:
Examples:
$ cat istio-mtls-permissive.yaml
$ cat file.yaml
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
@ -51,7 +51,7 @@ Examples:
tls:
mode: ISTIO_MUTUAL
$ cat istio-mtls-permissive.yaml | jc --yaml -p
$ cat file.yaml | jc --yaml -p
[
{
"apiVersion": "authentication.istio.io/v1alpha1",

View File

@ -99,4 +99,4 @@ Returns:
### Parser Information
Compatibility: linux, darwin
Version 1.1 by Matt J (https://github.com/listuser)
Version 1.2 by Matt J (https://github.com/listuser)

View File

@ -6,10 +6,6 @@ Parses standard `INI` files.
- Comment prefix can be `#` or `;`. Comments must be on their own line.
- If duplicate keys are found, only the last value will be used.
> Note: If there is no top-level section identifier, then this parser will
> add a key named `_top_level_section_` with the top-level key/values
> included.
> Note: The section identifier `[DEFAULT]` is special and provides default
> values for the section keys that follow. To disable this behavior you must
> rename the `[DEFAULT]` section identifier to something else before
@ -42,39 +38,34 @@ standard library documentation for more details.
Examples:
$ cat example.ini
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
foo = bar
baz = buz
[bitbucket.org]
User = hg
[section1]
key1 = value1
key2 = value2
[topsecret.server.com]
Port = 50022
ForwardX11 = no
[section2]
key1 = value1
key2 = value2
$ cat example.ini | jc --ini -p
{
"bitbucket.org": {
"ServerAliveInterval": "45",
"Compression": "yes",
"CompressionLevel": "9",
"ForwardX11": "yes",
"User": "hg"
"foo": "bar",
"baz": "buz",
"section1": {
"key1": "value1",
"key2": "value2"
},
"topsecret.server.com": {
"ServerAliveInterval": "45",
"Compression": "yes",
"CompressionLevel": "9",
"ForwardX11": "no",
"Port": "50022"
"section2": {
"key1": "value1",
"key2": "value2"
}
}
"""
import jc.utils
import configparser
import uuid
class info():
@ -91,6 +82,19 @@ class info():
__version__ = info.version
def _remove_quotes(value):
if value is None:
value = ''
elif value.startswith('"') and value.endswith('"'):
value = value[1:-1]
elif value.startswith("'") and value.endswith("'"):
value = value[1:-1]
return value
def _process(proc_data):
"""
Final processing to conform to the schema.
@ -104,16 +108,13 @@ def _process(proc_data):
Dictionary representing the INI file.
"""
# remove quotation marks from beginning and end of values
for heading in proc_data:
for key, value in proc_data[heading].items():
if value is not None and value.startswith('"') and value.endswith('"'):
proc_data[heading][key] = value[1:-1]
for k, v in proc_data.items():
if isinstance(v, dict):
for key, value in v.items():
v[key] = _remove_quotes(value)
continue
elif value is not None and value.startswith("'") and value.endswith("'"):
proc_data[heading][key] = value[1:-1]
elif value is None:
proc_data[heading][key] = ''
proc_data[k] = _remove_quotes(v)
return proc_data
@ -153,11 +154,21 @@ def parse(data, raw=False, quiet=False):
raw_output = {s: dict(ini_parser.items(s)) for s in ini_parser.sections()}
except configparser.MissingSectionHeaderError:
data = '[_top_level_section_]\n' + data
ini_parser.read_string(data)
raw_output = {s: dict(ini_parser.items(s)) for s in ini_parser.sections()}
# find a top-level section name that will not collide with any existing ones
while True:
my_uuid = str(uuid.uuid4())
if my_uuid not in data:
break
data = f'[{my_uuid}]\n' + data
ini_parser.read_string(data)
temp_dict = {s: dict(ini_parser.items(s)) for s in ini_parser.sections()}
# move items under fake top-level sections to the root
raw_output = temp_dict.pop(my_uuid)
# get the rest of the sections
raw_output.update(temp_dict)
return raw_output if raw else _process(raw_output)
if raw:
return raw_output
else:
return _process(raw_output)

View File

@ -82,15 +82,15 @@ def _process(proc_data):
"""
# remove quotation marks from beginning and end of values
for key in proc_data:
if proc_data[key] is not None and proc_data[key].startswith('"') and proc_data[key].endswith('"'):
proc_data[key] = proc_data[key][1:-1]
elif proc_data[key] is not None and proc_data[key].startswith("'") and proc_data[key].endswith("'"):
proc_data[key] = proc_data[key][1:-1]
elif proc_data[key] is None:
if proc_data[key] is None:
proc_data[key] = ''
elif proc_data[key].startswith('"') and proc_data[key].endswith('"'):
proc_data[key] = proc_data[key][1:-1]
elif proc_data[key].startswith("'") and proc_data[key].endswith("'"):
proc_data[key] = proc_data[key][1:-1]
return proc_data
@ -130,8 +130,5 @@ def parse(data, raw=False, quiet=False):
for key, value in output_dict['data'].items():
raw_output[key] = value
if raw:
return raw_output
else:
return _process(raw_output)
return raw_output if raw else _process(raw_output)

View File

@ -341,6 +341,7 @@ class _root_obj:
if '_state' in item[keyname] and item[keyname]['_state']['bus_idx'] == bus_idx:
return True
return False
def _update_output(self, bus_idx, output_line):
@ -370,7 +371,8 @@ class _descriptor_obj:
self.list = []
def _entries_for_this_bus_and_interface_idx_exist(self, bus_idx, iface_idx):
"""Returns true if there are object entries for the corresponding bus index and interface index"""
"""Returns true if there are object entries for the corresponding bus index
and interface index"""
for item in self.list:
keyname = tuple(item.keys())[0]
@ -378,11 +380,12 @@ class _descriptor_obj:
and item[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
return True
return False
def _update_output(self, bus_idx, iface_idx, output_line):
"""modifies output_line dictionary for the corresponding bus index and interface index.
output_line is the i_desc_obj object."""
"""modifies output_line dictionary for the corresponding bus index and
interface index. output_line is the i_desc_obj object."""
for item in self.list:
keyname = tuple(item.keys())[0]
@ -409,7 +412,8 @@ class _descriptor_list:
self.list = []
def _entries_for_this_bus_and_interface_idx_exist(self, bus_idx, iface_idx):
"""Returns true if there are object entries for the corresponding bus index and interface index"""
"""Returns true if there are object entries for the corresponding bus index
and interface index"""
for item in self.list:
keyname = tuple(item.keys())[0]
@ -417,10 +421,12 @@ class _descriptor_list:
and item[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
return True
return False
def _get_objects_list(self, bus_idx, iface_idx):
"""Returns a list of descriptor object dictionaries for the corresponding bus index and interface index"""
"""Returns a list of descriptor object dictionaries for the corresponding
bus index and interface index"""
object_collection = []
# find max number of items in this object that match the bus_idx and iface_idx
@ -458,6 +464,7 @@ class _descriptor_list:
del item[keyname]['_state']
object_collection.append(this_object)
return object_collection
@ -489,7 +496,6 @@ class _LsUsb():
self.configuration_descriptor = _root_obj('configuration_descriptor')
self.interface_association = _root_obj('interface_association')
self.interface_descriptor_list = []
self.interface_descriptor_attribute_list = []
self.cdc_header = _descriptor_obj('cdc_header')
self.cdc_call_management = _descriptor_obj('cdc_call_management')
self.cdc_acm = _descriptor_obj('cdc_acm')
@ -498,7 +504,7 @@ class _LsUsb():
self.videocontrol_interface_descriptors = _descriptor_list('videocontrol_interface_descriptor')
self.videostreaming_interface_descriptors = _descriptor_list('videostreaming_interface_descriptor')
self.hid_device_descriptor = _descriptor_obj('hid_device_descriptor')
self.report_descriptors_list = []
# self.report_descriptors_list = [] # not implemented
self.hub_descriptor = _root_obj('hub_descriptor')
self.hub_port_status_list = []
self.device_qualifier_list = []
@ -628,7 +634,7 @@ class _LsUsb():
)
return True
# This section is a list, so need to update indexes
# These sections are lists, so need to update indexes
if line.startswith(' Interface Descriptor:'):
self.section = 'interface_descriptor'
self.interface_descriptor_idx += 1
@ -638,21 +644,18 @@ class _LsUsb():
self.attribute_value = False
return True
# This section is a list, so need to update the index
if line.startswith(' Endpoint Descriptor:'):
self.section = 'endpoint_descriptor'
self.endpoint_descriptor_idx += 1
self.attribute_value = False
return True
# This section is a list, so need to update the index
if line.startswith(' VideoControl Interface Descriptor:'):
self.section = 'videocontrol_interface_descriptor'
self.videocontrol_interface_descriptor_idx += 1
self.attribute_value = False
return True
# This section is a list, so need to update the index
if line.startswith(' VideoStreaming Interface Descriptor:'):
self.section = 'videostreaming_interface_descriptor'
self.videostreaming_interface_descriptor_idx += 1
@ -711,7 +714,7 @@ class _LsUsb():
'cdc_acm': self.cdc_acm.list,
'cdc_union': self.cdc_union.list,
'hid_device_descriptor': self.hid_device_descriptor.list,
'report_descriptors': self.report_descriptors_list,
# 'report_descriptors': self.report_descriptors_list, # not implemented
'videocontrol_interface_descriptor': self.videocontrol_interface_descriptors.list,
'videostreaming_interface_descriptor': self.videostreaming_interface_descriptors.list,
'endpoint_descriptor': self.endpoint_descriptors.list,
@ -771,17 +774,15 @@ class _LsUsb():
del item['_state']
self.output_line.update(item)
# add device_descriptor key
# add initial root-level keys
if self.device_descriptor._entries_for_this_bus_exist(idx):
self.device_descriptor._update_output(idx, self.output_line)
# add configuration_descriptor key
if self.configuration_descriptor._entries_for_this_bus_exist(idx):
self.configuration_descriptor._update_output(
idx, self.output_line['device_descriptor']
)
# add interface_association key
if self.interface_association._entries_for_this_bus_exist(idx):
self.interface_association._update_output(
idx, self.output_line['device_descriptor']['configuration_descriptor']
@ -812,7 +813,6 @@ class _LsUsb():
for iface_idx in range(i_desc_iters + 1):
i_desc_obj = _NestedDict()
## interface_descriptor_list _root object?
for iface_attrs in self.interface_descriptor_list:
keyname = tuple(iface_attrs.keys())[0]
@ -834,28 +834,19 @@ class _LsUsb():
del iface_attrs[keyname]['_state']
i_desc_obj.update(iface_attrs)
# add cdc_header key if it doesn't exist and there are
# entries for this interface_descriptor
# add the rest of the interface descriptor keys to the object
if self.cdc_header._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
self.cdc_header._update_output(idx, iface_idx, i_desc_obj)
# add cdc_call_management key if it doesn't exist and there are
# entries for this interface_descriptor
if self.cdc_call_management._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
self.cdc_call_management._update_output(idx, iface_idx, i_desc_obj)
# add cdc_acm key if it doesn't exist and there are entries for
# this interface_descriptor
if self.cdc_acm._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
self.cdc_acm._update_output(idx, iface_idx, i_desc_obj)
# add cdc_union key if it doesn't exist and there are entries for
# this interface_descriptor
if self.cdc_union._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
self.cdc_union._update_output(idx, iface_idx, i_desc_obj)
# add hid_device_descriptor key if it doesn't exist and there are
# entries for this interface_descriptor
if self.hid_device_descriptor._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
self.hid_device_descriptor._update_output(idx, iface_idx, i_desc_obj)
@ -866,24 +857,18 @@ class _LsUsb():
# i_desc_obj['hid_device_descriptor']['report_descriptors'].update(rd)
# del i_desc_obj['hid_device_descriptor']['report_descriptors'][keyname]['_state']
# add videocontrol_interface_descriptors key if it doesn't exist
# and there are entries for this interface_descriptor
if self.videocontrol_interface_descriptors._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
i_desc_obj['videocontrol_interface_descriptors'] = []
i_desc_obj['videocontrol_interface_descriptors'].extend(
self.videocontrol_interface_descriptors._get_objects_list(idx, iface_idx)
)
# add videostreaming_interface_descriptors key if it doesn't exist
# and there are entries for this interface_descriptor
if self.videostreaming_interface_descriptors._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
i_desc_obj['videostreaming_interface_descriptors'] = []
i_desc_obj['videostreaming_interface_descriptors'].extend(
self.videostreaming_interface_descriptors._get_objects_list(idx, iface_idx)
)
# add endpoint_descriptors key if it doesn't exist and there are
# entries for this interface_descriptor
if self.endpoint_descriptors._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
i_desc_obj['endpoint_descriptors'] = []
i_desc_obj['endpoint_descriptors'].extend(
@ -893,8 +878,7 @@ class _LsUsb():
# add the object to the list of interface descriptors
self.output_line['device_descriptor']['configuration_descriptor']['interface_descriptors'].append(i_desc_obj)
# add hub_descriptor key if it doesn't exist and there are
# entries for this interface_descriptor
# add final root-level keys
if self.hub_descriptor._entries_for_this_bus_exist(idx):
self.hub_descriptor._update_output(idx, self.output_line)

View File

@ -7,25 +7,48 @@ Usage (cli):
Usage (module):
import jc
result = jc.parse('toml', toml_file)
result = jc.parse('toml', toml_file_output)
Schema:
[
TOML Document converted to a Dictionary.
See https://toml.io/en/ for details.
{
"toml": string,
"bar": boolean,
"baz": integer
"key1": string/int/float/boolean/null/array/object,
"key2": string/int/float/boolean/null/array/object
}
]
Examples:
$ toml | jc --toml -p
[]
$ cat file.toml
title = "TOML Example"
$ toml | jc --toml -p -r
[]
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00
[database]
enabled = true
ports = [ 8000, 8001, 8002 ]
$ cat file.toml | jc --toml -p
{
"title": "TOML Example",
"owner": {
"name": "Tom Preston-Werner",
"dob": 296667120,
"dob_iso": "1979-05-27T07:32:00-08:00"
},
"database": {
"enabled": true,
"ports": [
8000,
8001,
8002
]
}
}
"""
from typing import Any
from jc.jc_types import JSONDictType

View File

@ -13,8 +13,8 @@ Usage (module):
Schema:
YAML Document converted to a Dictionary
See https://pypi.org/project/ruamel.yaml for details
YAML Document converted to a Dictionary.
See https://pypi.org/project/ruamel.yaml for details.
[
{
@ -25,7 +25,7 @@ Schema:
Examples:
$ cat istio-mtls-permissive.yaml
$ cat file.yaml
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
@ -46,7 +46,7 @@ Examples:
tls:
mode: ISTIO_MUTUAL
$ cat istio-mtls-permissive.yaml | jc --yaml -p
$ cat file.yaml | jc --yaml -p
[
{
"apiVersion": "authentication.istio.io/v1alpha1",

View File

@ -77,7 +77,7 @@ import jc.parsers.universal
class info():
"""Provides parser metadata (version, author, etc.)"""
version = '1.1'
version = '1.2'
description = '`zipinfo` command parser'
author = 'Matt J'
author_email = 'https://github.com/listuser'
@ -170,7 +170,8 @@ def parse(data, raw=False, quiet=False):
# 1st line
# Archive: log4j-core-2.16.0.jar
line = archive_item.pop(0)
_, archive = line.split()
# remove prefix but don't split on spaces for files/paths with spaces
archive = line.replace('Archive: ', '', 1)
# 2nd line
# Zip file size: 1789565 bytes, number of entries: 1218

View File

@ -1,4 +1,4 @@
.TH jc 1 2023-01-05 1.22.5 "JSON Convert"
.TH jc 1 2023-01-06 1.22.5 "JSON Convert"
.SH NAME
\fBjc\fP \- JSON Convert JSONifies the output of many CLI tools, file-types, and strings
.SH SYNOPSIS

View File

@ -0,0 +1 @@
{"title":"TOML Example","owner":{"name":"Lance Uppercut","dob":296667120,"dob_iso":"1979-05-27T07:32:00-08:00"},"database":{"server":"192.168.1.1","ports":[8001,8001,8002],"connection_max":5000,"enabled":true},"servers":{"alpha":{"ip":"10.0.0.1","dc":"eqdc10"},"beta":{"ip":"10.0.0.2","dc":"eqdc10"}},"clients":{"data":[["gamma","delta"],[1,2]],"hosts":["alpha","omega"]}}

View File

@ -0,0 +1,27 @@
{
"fruit": [
{
"name": "apple",
"physical": {
"color": "red",
"shape": "round"
},
"variety": [
{
"name": "red delicious"
},
{
"name": "granny smith"
}
]
},
{
"name": "banana",
"variety": [
{
"name": "plantain"
}
]
}
]
}

View File

@ -0,0 +1,18 @@
[[fruit]]
name = "apple"
[fruit.physical]
color = "red"
shape = "round"
[[fruit.variety]]
name = "red delicious"
[[fruit.variety]]
name = "granny smith"
[[fruit]]
name = "banana"
[[fruit.variety]]
name = "plantain"

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -76,14 +76,19 @@ key: value1
another_key = foo
[section2]
key3: bar
key4 =
[section 3]
key5 = "quoted"
'''
expected = {
'_top_level_section_': {
'key': 'value1',
'another_key': 'foo'
},
'another_key': 'foo',
'section2': {
'key3': 'bar'
'key3': 'bar',
'key4': ''
},
'section 3': {
'key5': 'quoted'
}
}
self.assertEqual(jc.parsers.ini.parse(data, quiet=True), expected)

59
tests/test_toml.py Normal file
View File

@ -0,0 +1,59 @@
import os
import unittest
import json
from typing import Dict
from jc.parsers.toml import parse
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
class MyTests(unittest.TestCase):
f_in: Dict = {}
f_json: Dict = {}
@classmethod
def setUpClass(cls):
fixtures = {
'toml1': (
'fixtures/generic/toml-example.toml',
'fixtures/generic/toml-example.json'),
'toml2': (
'fixtures/generic/toml-example2.toml',
'fixtures/generic/toml-example2.json')
}
for file, filepaths in fixtures.items():
with open(os.path.join(THIS_DIR, filepaths[0]), 'r', encoding='utf-8') as a, \
open(os.path.join(THIS_DIR, filepaths[1]), 'r', encoding='utf-8') as b:
cls.f_in[file] = a.read()
cls.f_json[file] = json.loads(b.read())
def test_toml_nodata(self):
"""
Test 'toml' with no data
"""
self.assertEqual(parse('', quiet=True), {})
def test_toml_example1(self):
"""
Test 'toml' with first example file
"""
self.assertEqual(
parse(self.f_in['toml1'], quiet=True),
self.f_json['toml1']
)
def test_toml_example2(self):
"""
Test 'toml' with second example file
"""
self.assertEqual(
parse(self.f_in['toml2'], quiet=True),
self.f_json['toml2']
)
if __name__ == '__main__':
unittest.main()

View File

@ -15,6 +15,9 @@ class MyTests(unittest.TestCase):
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/zipinfo-multi.out'), 'r', encoding='utf-8') as f:
osx_10_14_6_zipinfo_multi = f.read()
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/rhel-8/zipinfo-space-in-name.out'), 'r', encoding='utf-8') as f:
rhel_8_zipinfo_space_in_name = f.read()
# output
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/rhel-8/zipinfo.json'), 'r', encoding='utf-8') as f:
rhel_8_zipinfo_json = json.loads(f.read())
@ -22,6 +25,9 @@ class MyTests(unittest.TestCase):
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/zipinfo-multi.json'), 'r', encoding='utf-8') as f:
osx_10_14_6_zipinfo_multi_json = json.loads(f.read())
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/rhel-8/zipinfo-space-in-name.json'), 'r', encoding='utf-8') as f:
rhel_8_zipinfo_space_in_name_json = json.loads(f.read())
def test_zipinfo_nodata(self):
"""
@ -41,6 +47,12 @@ class MyTests(unittest.TestCase):
"""
self.assertEqual(jc.parsers.zipinfo.parse(self.osx_10_14_6_zipinfo_multi, quiet=True), self.osx_10_14_6_zipinfo_multi_json)
def test_zipinfo_rhel_8_space_in_name(self):
"""
Test 'zipinfo' on Red Hat 8 with spaces in the file path
"""
self.assertEqual(jc.parsers.zipinfo.parse(self.rhel_8_zipinfo_space_in_name, quiet=True), self.rhel_8_zipinfo_space_in_name_json)
if __name__ == '__main__':
unittest.main()