Skip to content

Commit

Permalink
Fixed #2
Browse files Browse the repository at this point in the history
Moved unit test to test dir
  • Loading branch information
En3rGy committed Mar 17, 2023
1 parent 3d68b50 commit c63f444
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 132 deletions.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ Beispiel für eine Bausteinkaskade, mit JSON-String = `{"1": "a", "2":[{"2.1": "

## Eingänge

| Nr. | Name | Initialisierung | Beschreibung |
|-----|-------------|-----------------|---------------------------------------------------------------------------------------------|
| 1 | JSON-String | | Gültiger (!) JSON-String |
| 2 | Key | | JSON Key, für den der Wert ausgegeben werden soll.<br>*Wird nur verwendet, wenn Array Index < 0!* |
| Nr. | Name | Initialisierung | Beschreibung |
|-----|-------------|-----------------|------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 | JSON-String | | Gültiger (!) JSON-String |
| 2 | Key | | JSON Key, für den der Wert ausgegeben werden soll.<br>*Wird nur verwendet, wenn Array Index < 0!* |
| 3 | Array Index | -1 | Index des Array Elements, welches ausgegeben werden soll. Das erste Element hat den Index 0<br>*Wenn >= 0 wird immer der Index verwendet und nie der Key!* |

## Ausgänge

| Nr. | Name | Initialisierung | Beschreibung |
|-----|----------------|-----------------|--------------------------------------------------|
| 1 | Value (str) | | Angefragter Wert oder JSON-Struktur |
| 2 | Value (number) | 0 | Angefragter Wert als Zahl (float, int oder bool) |
| Nr. | Name | Initialisierung | Beschreibung |
|-----|----------------|-----------------|----------------------------------------------------------------------------------------|
| 1 | Value (str) | | Angefragter Wert oder JSON-Struktur; XML enkodiert, falls UTF-8 Zeichen enthalten sind |
| 2 | Value (number) | 0 | Angefragter Wert als Zahl (float, int oder bool) |

## Sonstiges

Expand All @@ -34,6 +34,8 @@ Beispiel für eine Bausteinkaskade, mit JSON-String = `{"1": "a", "2":[{"2.1": "

### Change Log

- v1.4
- XML encoded output if UTF-8 characters would be part of the output
- v1.3
- added unit tests
- improved reliability / stability
Expand Down
2 changes: 1 addition & 1 deletion config.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<config>
<modules>
<module category="Datenaustausch" context="hsl20_4_json" id="11087" name="JSON_Parser (11087)" version="1.3">
<module category="Datenaustausch" context="hsl20_4_json" id="11087" name="JSON_Parser (11087)" version="1.4">
<inputs>
<input type="string" const_name="sJson" init_value="">JSON-String</input>
<input type="string" const_name="sKey" init_value="">Key</input>
Expand Down
25 changes: 18 additions & 7 deletions src/11087_JSON_Parser (11087).py
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,34 @@ def get_list_element(self, s_json, n_index):

return False, "{}"

def get_value(self, s_json, s_key):
def get_value(self, json_file, key):
"""
:param json_file:
:type json_file: unicode or non-unicode string
:param key:
:type key: non-unicode string
:return:
"""
try:
json_file = json.loads(s_json)
json_file = json.loads(json_file)
except ValueError as e:
self.DEBUG.add_message('In get_value:129, "' + e.message + '" with\n' + s_json)
self.DEBUG.add_message('In get_value:129, "{}" with \n{}'.format(e.message, json_file))
return False, str()

if not isinstance(key, unicode):
key = key.decode('utf-8')

ret = ""
if s_key in json_file:
val = json_file[s_key]
if key in json_file:
val = json_file[key]

if isinstance(val, dict) or isinstance(val, list):
ret = json.dumps(val)
else:
ret = val

if isinstance(ret, str):
if isinstance(ret, unicode):
ret = ret.encode("ascii", "xmlcharrefreplace")

else:
Expand Down Expand Up @@ -103,4 +114,4 @@ def on_input_value(self, index, value):
except:
pass

self._set_output_value(self.PIN_O_SVALUE, str(val))
self._set_output_value(self.PIN_O_SVALUE, str(val).encode("ascii", "xmlcharrefreplace"))
134 changes: 18 additions & 116 deletions src/test_JSON_Parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,23 +122,34 @@ def get_list_element(self, s_json, n_index):

return False, "{}"

def get_value(self, s_json, s_key):
def get_value(self, json_file, key):
"""
:param json_file:
:type json_file: unicode or non-unicode string
:param key:
:type key: non-unicode string
:return:
"""
try:
json_file = json.loads(s_json)
json_file = json.loads(json_file)
except ValueError as e:
self.DEBUG.add_message('In get_value:129, "' + e.message + '" with\n' + s_json)
self.DEBUG.add_message('In get_value:129, "{}" with \n{}'.format(e.message, json_file))
return False, str()

if not isinstance(key, unicode):
key = key.decode('utf-8')

ret = ""
if s_key in json_file:
val = json_file[s_key]
if key in json_file:
val = json_file[key]

if isinstance(val, dict) or isinstance(val, list):
ret = json.dumps(val)
else:
ret = val

if isinstance(ret, str):
if isinstance(ret, unicode):
ret = ret.encode("ascii", "xmlcharrefreplace")

else:
Expand Down Expand Up @@ -190,113 +201,4 @@ def on_input_value(self, index, value):
except:
pass

self._set_output_value(self.PIN_O_SVALUE, str(val))


############################################

class JsonTests(unittest.TestCase):

def setUp(self):
self.dummy = JSON_Parser_11087_11087(0)
self.dummy.on_init()

def tearDown(self):
pass

def test_error_json(self):
in_json = '{"test":1, "dummy":2 "go": 3}'
self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = in_json
self.dummy.debug_input_value[self.dummy.PIN_I_SKEY] = "go"
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = -1

self.dummy.on_input_value(self.dummy.PIN_I_SKEY, "go")

self.assertTrue(True)

def test_getValue_str(self):
in_text = '{"siteCurrentPowerFlow":{"updateRefreshRate":3,"unit":"kW","connections":[{"from":"STORAGE",' \
'"to":"Load"},{"from":"GRID","to":"Load"}],"GRID":{"status":"Active","currentPower":0.01},' \
'"LOAD":{"status":"Active","currentPower":1.37},"PV":{"status":"Idle","currentPower":0.0},' \
'"STORAGE":{"status":"Discharging","currentPower":1.36,"chargeLevel":38,"critical":false}}} '

ok, ret = self.dummy.get_value(in_text, "siteCurrentPowerFlow")
res = '{"LOAD": {"status": "Active", "currentPower": 1.37}, "PV": {"status": "Idle", "currentPower": 0.0}, ' \
'"STORAGE": {"status": "Discharging", "critical": false, "chargeLevel": 38, "currentPower": 1.36}, ' \
'"connections": [{"to": "Load", "from": "STORAGE"}, {"to": "Load", "from": "GRID"}], "GRID": {"status": ' \
'"Active", "currentPower": 0.01}, "updateRefreshRate": 3, "unit": "kW"} '
self.assertTrue(ok)
self.assertEqual(json.loads(ret), json.loads(res))

def test_getValue_int(self):
ret = '{"LOAD": {"status": "Active", "currentPower": 1.37}, "PV": {"status": "Idle", "currentPower": 0.0}, ' \
'"STORAGE": {"status": "Discharging", "critical": false, "chargeLevel": 38, "currentPower": 1.36}, ' \
'"connections": [{"to": "Load", "from": "STORAGE"}, {"to": "Load", "from": "GRID"}], "GRID": {"status": ' \
'"Active", "currentPower": 0.01}, "updateRefreshRate": 3, "unit": "kW"} '
ok, ret = self.dummy.get_value(ret, "updateRefreshRate")
self.assertTrue(ok)
self.assertEqual(ret, 3)

def test_index(self):
ret = '["LOAD", "Active", "PV"]'
self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret
self.dummy.debug_input_value[self.dummy.PIN_I_SKEY] = str()
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = 1

self.dummy.on_input_value(self.dummy.PIN_I_NIDX, 1)

ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]
self.assertEqual(ret, 'Active')

ret = '[["LOAD", "Active", "PV"], [1, 2, 3]]'
self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret

self.dummy.on_input_value(self.dummy.PIN_I_NIDX, 1)

ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]
self.assertEqual(ret, "[1, 2, 3]")

def test_key(self):
ret = '{"LOAD": {"status": "Active", "currentPower": 1.37}, "PV": {"status": "Idle", "currentPower": 0.0}, ' \
'"STORAGE": {"status": "Discharging", "critical": false, "chargeLevel": 38, "currentPower": 1.36}, ' \
'"connections": [{"to": "Load", "from": "STORAGE"}, {"to": "Load", "from": "GRID"}], "GRID": {"status": ' \
'"Active", "currentPower": 0.01}, "updateRefreshRate": 3, "unit": "kW"} '

self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret
self.dummy.debug_input_value[self.dummy.PIN_I_SKEY] = "updateRefreshRate"
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = -1

self.dummy.on_input_value(self.dummy.PIN_I_NIDX, -1)

ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]
self.assertEqual(ret, "3")

ret = self.dummy.debug_output_value[self.dummy.PIN_O_FVALUE]
self.assertEqual(ret, 3)

def test_kaskade(self):
ret = '{"1": "a", "2":[{"2.1": "b.1", "2.2": "b.2"}, {"2.3": "b.3"}]}'
self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = -1
self.dummy.debug_input_value[self.dummy.PIN_I_SKEY] = "2"

self.dummy.on_input_value(self.dummy.PIN_I_SKEY, "2")
ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]
self.assertEqual(json.loads('[{"2.1": "b.1", "2.2": "b.2"}, {"2.3": "b.3"}]'), json.loads(ret))

self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = 0
self.dummy.on_input_value(self.dummy.PIN_I_NIDX, 0)
ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]
self.assertEqual(json.loads('{"2.1": "b.1", "2.2": "b.2"}'), json.loads(ret))

self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = -1
self.dummy.debug_input_value[self.dummy.PIN_I_SKEY] = "2.2"
self.dummy.on_input_value(self.dummy.PIN_I_SKEY, "2.2")
ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]

self.assertEqual("b.2", ret)

if __name__ == '__main__':
unittest.main()
self._set_output_value(self.PIN_O_SVALUE, str(val).encode("ascii", "xmlcharrefreplace"))
130 changes: 130 additions & 0 deletions tests/tst_JSON_Parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# coding: utf8

import unittest
import time
import json
import random

from test_JSON_Parser import JSON_Parser_11087_11087


class JsonTests(unittest.TestCase):

def setUp(self):
self.dummy = JSON_Parser_11087_11087(0)
self.dummy.on_init()

def tearDown(self):
pass

def test_error_json(self):
in_json = '{"test":1, "dummy":2 "go": 3}'
self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = in_json
self.dummy.debug_input_value[self.dummy.PIN_I_SKEY] = "go"
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = -1

self.dummy.on_input_value(self.dummy.PIN_I_SKEY, "go")

self.assertTrue(True)

def test_getValue_str(self):
in_text = '{"siteCurrentPowerFlow":{"updateRefreshRate":3,"unit":"kW","connections":[{"from":"STORAGE",' \
'"to":"Load"},{"from":"GRID","to":"Load"}],"GRID":{"status":"Active","currentPower":0.01},' \
'"LOAD":{"status":"Active","currentPower":1.37},"PV":{"status":"Idle","currentPower":0.0},' \
'"STORAGE":{"status":"Discharging","currentPower":1.36,"chargeLevel":38,"critical":false}}} '

ok, ret = self.dummy.get_value(in_text, "siteCurrentPowerFlow")
res = '{"LOAD": {"status": "Active", "currentPower": 1.37}, "PV": {"status": "Idle", "currentPower": 0.0}, ' \
'"STORAGE": {"status": "Discharging", "critical": false, "chargeLevel": 38, "currentPower": 1.36}, ' \
'"connections": [{"to": "Load", "from": "STORAGE"}, {"to": "Load", "from": "GRID"}], "GRID": {"status": ' \
'"Active", "currentPower": 0.01}, "updateRefreshRate": 3, "unit": "kW"} '
self.assertTrue(ok)
self.assertEqual(json.loads(ret), json.loads(res))

def test_getValue_int(self):
ret = '{"LOAD": {"status": "Active", "currentPower": 1.37}, "PV": {"status": "Idle", "currentPower": 0.0}, ' \
'"STORAGE": {"status": "Discharging", "critical": false, "chargeLevel": 38, "currentPower": 1.36}, ' \
'"connections": [{"to": "Load", "from": "STORAGE"}, {"to": "Load", "from": "GRID"}], "GRID": {"status": ' \
'"Active", "currentPower": 0.01}, "updateRefreshRate": 3, "unit": "kW"} '
ok, ret = self.dummy.get_value(ret, "updateRefreshRate")
self.assertTrue(ok)
self.assertEqual(ret, 3)

def test_index(self):
ret = '["LOAD", "Active", "PV"]'
self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret
self.dummy.debug_input_value[self.dummy.PIN_I_SKEY] = str()
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = 1

self.dummy.on_input_value(self.dummy.PIN_I_NIDX, 1)

ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]
self.assertEqual(ret, 'Active')

ret = '[["LOAD", "Active", "PV"], [1, 2, 3]]'
self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret

self.dummy.on_input_value(self.dummy.PIN_I_NIDX, 1)

ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]
self.assertEqual(ret, "[1, 2, 3]")

def test_key(self):
ret = '{"LOAD": {"status": "Active", "currentPower": 1.37}, "PV": {"status": "Idle", "currentPower": 0.0}, ' \
'"STORAGE": {"status": "Discharging", "critical": false, "chargeLevel": 38, "currentPower": 1.36}, ' \
'"connections": [{"to": "Load", "from": "STORAGE"}, {"to": "Load", "from": "GRID"}], "GRID": {"status": ' \
'"Active", "currentPower": 0.01}, "updateRefreshRate": 3, "unit": "kW"} '

self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret
self.dummy.debug_input_value[self.dummy.PIN_I_SKEY] = "updateRefreshRate"
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = -1

self.dummy.on_input_value(self.dummy.PIN_I_NIDX, -1)

ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]
self.assertEqual(ret, "3")

ret = self.dummy.debug_output_value[self.dummy.PIN_O_FVALUE]
self.assertEqual(ret, 3)

def test_kaskade(self):
ret = '{"1": "a", "2":[{"2.1": "b.1", "2.2": "b.2"}, {"2.3": "b.3"}]}'
self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = -1
self.dummy.debug_input_value[self.dummy.PIN_I_SKEY] = "2"

self.dummy.on_input_value(self.dummy.PIN_I_SKEY, "2")
ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]
self.assertEqual(json.loads('[{"2.1": "b.1", "2.2": "b.2"}, {"2.3": "b.3"}]'), json.loads(ret))

self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = 0
self.dummy.on_input_value(self.dummy.PIN_I_NIDX, 0)
ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]
self.assertEqual(json.loads('{"2.1": "b.1", "2.2": "b.2"}'), json.loads(ret))

self.dummy.debug_input_value[self.dummy.PIN_I_SJSON] = ret
self.dummy.debug_input_value[self.dummy.PIN_I_NIDX] = -1
self.dummy.debug_input_value[self.dummy.PIN_I_SKEY] = "2.2"
self.dummy.on_input_value(self.dummy.PIN_I_SKEY, "2.2")
ret = self.dummy.debug_output_value[self.dummy.PIN_O_SVALUE]

self.assertEqual("b.2", ret)

def test_unicode(self):
in_val = u'{"2.1": "Äö", "2.2": "b.2"}'

ok, ret = self.dummy.get_value(in_val, "2.1")
res = '&#196;&#246;'
self.assertTrue(ok)
self.assertEqual(ret, res)
ok, ret = self.dummy.get_value(in_val, u"2.1")
self.assertTrue(ok)
self.assertEqual(ret, res)
ok, ret = self.dummy.get_value(in_val, u"2.2")
self.assertTrue(ok)
self.assertEqual(ret, "b.2")


if __name__ == '__main__':
unittest.main()

0 comments on commit c63f444

Please sign in to comment.