diff --git a/checkers/common.py b/checkers/common.py new file mode 100644 index 0000000..4d4ed41 --- /dev/null +++ b/checkers/common.py @@ -0,0 +1,129 @@ +import logging +from itertools import chain + + +def floats_eq(a, b): + return abs(b - a) < 1e-13 + + +def coords_eq(lon1, lat1, lon2, lat2): + return floats_eq(lon1, lon2) and floats_eq(lat1, lat2) + + +def osm_id_comparator(el): + """This function is used as key for sorting lists of + OSM-originated objects + """ + return (el['osm_type'], el['osm_id']) + + +def compare_stops(stop0, stop1): + """Compares json of two stops in route""" + stop_keys = ('name', 'int_name', 'id', 'osm_id', 'osm_type') + stop0_props = tuple(stop0[k] for k in stop_keys) + stop1_props = tuple(stop1[k] for k in stop_keys) + + if stop0_props != stop1_props: + logging.debug("Different stops properties: %s, %s", + stop0_props, stop1_props) + return False + + if not coords_eq(stop0['lon'], stop0['lat'], + stop1['lon'], stop1['lat']): + logging.debug("Different stops coordinates: %s (%f, %f), %s (%f, %f)", + stop0_props, stop0['lon'], stop0['lat'], + stop1_props, stop1['lon'], stop1['lat']) + return False + + entrances0 = sorted(stop0['entrances'], key=osm_id_comparator) + entrances1 = sorted(stop1['entrances'], key=osm_id_comparator) + if entrances0 != entrances1: + logging.debug("Different stop entrances") + return False + + exits0 = sorted(stop0['exits'], key=osm_id_comparator) + exits1 = sorted(stop1['exits'], key=osm_id_comparator) + if exits0 != exits1: + logging.debug("Different stop exits") + return False + + return True + + +def compare_transfers(transfers0, transfers1): + """Compares two arrays of transfers of the form + [(stop1_uid, stop2_uid, time), ...] + """ + if len(transfers0) != len(transfers1): + logging.debug("Different len(transfers): %d != %d", + len(transfers0), len(transfers1)) + return False + + transfers0 = [tuple(t) if t[0] < t[1] else tuple([t[1], t[0], t[2]]) + for t in transfers0] + transfers1 = [tuple(t) if t[0] < t[1] else tuple([t[1], t[0], t[2]]) + for t in transfers1] + + transfers0.sort() + transfers1.sort() + + diff_cnt = 0 + for tr0, tr1 in zip(transfers0, transfers1): + if tr0 != tr1: + if diff_cnt == 0: + logging.debug("First pair of different transfers: %s, %s", + tr0, tr1) + diff_cnt += 1 + if diff_cnt: + logging.debug("Different transfers number = %d", diff_cnt) + return False + + return True + + +def compare_networks(network0, network1): + if network0['agency_id'] != network1['agency_id']: + logging.debug("Different agency_id at route '%s'", + network0['network']) + return False + + route_ids0 = sorted(x['route_id'] for x in network0['routes']) + route_ids1 = sorted(x['route_id'] for x in network1['routes']) + + if route_ids0 != route_ids1: + logging.debug("Different route_ids: %s != %s", + route_ids0, route_ids1) + return False + + routes0 = sorted(network0['routes'], key=lambda x: x['route_id']) + routes1 = sorted(network1['routes'], key=lambda x: x['route_id']) + + # Keys to compare routes. 'name' key is omitted since RouteMaster + # can get its name from one of its Routes unpredictably. + route_keys = ('type', 'ref', 'colour', 'route_id') + + for route0, route1 in zip(routes0, routes1): + route0_props = tuple(route0[k] for k in route_keys) + route1_props = tuple(route1[k] for k in route_keys) + if route0_props != route1_props: + logging.debug("Route props of '%s' are different: %s, %s", + route0['route_id'], route0_props, route1_props) + return False + + itineraries0 = sorted(route0['itineraries'], + key=lambda x: tuple(chain(*x['stops']))) + itineraries1 = sorted(route1['itineraries'], + key=lambda x: tuple(chain(*x['stops']))) + + for itin0, itin1 in zip(itineraries0, itineraries1): + if itin0['interval'] != itin1['interval']: + logging.debug("Different interval: %d != %d at route %s '%s'", + itin0['interval'], itin1['interval'], + route0['route_id'], route0['name']) + return False + if itin0['stops'] != itin1['stops']: + logging.debug("Different stops at route %s '%s'", + route0['route_id'], route0['name']) + return False + + return True diff --git a/checkers/compare_city_caches.py b/checkers/compare_city_caches.py index 8fad676..c6c81bc 100644 --- a/checkers/compare_city_caches.py +++ b/checkers/compare_city_caches.py @@ -12,133 +12,37 @@ import sys import json -from itertools import chain +import logging +from common import compare_stops, compare_transfers, compare_networks def compare_jsons(cache0, cache1): - - def floats_eq(a, b): - return abs(b - a) < 1e-13 - - def coords_eq(lon1, lat1, lon2, lat2): - return floats_eq(lon1, lon2) and floats_eq(lat1, lat2) - - def osm_id_comparator(el): - return (el['osm_type'], el['osm_id']) + """Compares two city caches""" city_names0 = sorted(cache0.keys()) city_names1 = sorted(cache1.keys()) - if city_names0 != city_names1: - print("Different list of city names!") + logging.debug("Different list of city names!") return False for name in city_names0: - result0 = cache0[name] - result1 = cache1[name] - - network0 = result0['network'] - network1 = result1['network'] - - if network0['agency_id'] != network1['agency_id']: - print("Different agency_id:", - network0['network'], network1['network']) + city0 = cache0[name] + city1 = cache1[name] + if not compare_networks(city0['network'], city1['network']): return False - # Keys to compare routes. 'name' key is omitted since RouteMaster - # can get its name from one of its Routes unpredictably. - route_keys = ('type', 'ref', 'colour', 'route_id') - - route_ids0 = sorted(x['route_id'] for x in network0['routes']) - route_ids1 = sorted(x['route_id'] for x in network1['routes']) - - if route_ids0 != route_ids1: - print("Different route_ids", route_ids0, route_ids1) - return False - - routes0 = sorted(network0['routes'], key=lambda x: x['route_id']) - routes1 = sorted(network1['routes'], key=lambda x: x['route_id']) - - for route0, route1 in zip(routes0, routes1): - route0_props = tuple(route0[k] for k in route_keys) - route1_props = tuple(route1[k] for k in route_keys) - if route0_props != route1_props: - print("Route props of ", route0['route_id'], route1['route_id'], - "are different:", route0_props, route1_props) - return False - - itineraries0 = sorted(route0['itineraries'], - key=lambda x: tuple(chain(*x['stops']))) - itineraries1 = sorted(route1['itineraries'], - key=lambda x: tuple(chain(*x['stops']))) - - for itin0, itin1 in zip(itineraries0, itineraries1): - if itin0['interval'] != itin1['interval']: - print("Different interval:", - itin0['interval'], "!=", itin1['interval'], - "at route", route0['name'], route0['route_id']) - return False - if itin0['stops'] != itin1['stops']: - print("Different stops at route", - route0['name'], route0['route_id']) - return False - - stop_ids0 = sorted(result0['stops'].keys()) - stop_ids1 = sorted(result1['stops'].keys()) + stop_ids0 = sorted(city0['stops'].keys()) + stop_ids1 = sorted(city1['stops'].keys()) if stop_ids0 != stop_ids1: - print("Different stop_ids") + logging.debug("Different stop_ids") return False - - stops0 = [v for k, v in sorted(result0['stops'].items())] - stops1 = [v for k, v in sorted(result1['stops'].items())] - + stops0 = [v for k, v in sorted(city0['stops'].items())] + stops1 = [v for k, v in sorted(city1['stops'].items())] for stop0, stop1 in zip(stops0, stops1): - stop0_props = tuple(stop0[k] for k in ('name', 'osm_id', 'osm_type')) - stop1_props = tuple(stop1[k] for k in ('name', 'osm_id', 'osm_type')) - if stop0_props != stop1_props: - print("Different stops properties:", stop0_props, stop1_props) - return False - if not coords_eq(stop0['lon'], stop0['lat'], - stop1['lon'], stop1['lat']): - print("Different stops coordinates:", - stop0_props, stop0['lon'], stop0['lat'], - stop1_props, stop1['lon'], stop1['lat']) + if not compare_stops(stop0, stop1): return False - entrances0 = sorted(stop0['entrances'], key=osm_id_comparator) - entrances1 = sorted(stop1['entrances'], key=osm_id_comparator) - if entrances0 != entrances1: - print("Different stop entrances") - return False - - exits0 = sorted(stop0['exits'], key=osm_id_comparator) - exits1 = sorted(stop1['exits'], key=osm_id_comparator) - if exits0 != exits1: - print("Different stop exits") - return False - - - if len(result0['transfers']) != len(result1['transfers']): - print("Different len(transfers):", - len(result0['transfers']), len(result1['transfers'])) - return False - - transfers0 = [tuple(t) if t[0] < t[1] else tuple([t[1], t[0], t[2]]) - for t in result0['transfers']] - transfers1 = [tuple(t) if t[0] < t[1] else tuple([t[1], t[0], t[2]]) - for t in result1['transfers']] - - transfers0.sort(key=lambda x: tuple(x)) - transfers1.sort(key=lambda x: tuple(x)) - - diff_cnt = 0 - for i, (tr0, tr1) in enumerate(zip(transfers0, transfers1)): - if tr0 != tr1: - if i == 0: - print("First pair of different transfers", tr0, tr1) - diff_cnt += 1 - if diff_cnt: - print("Different transfers number = ", diff_cnt) + if not compare_transfers(city0['transfers'], city1['transfers']): return False return True @@ -149,6 +53,8 @@ if __name__ == "__main__": print("Usage: {} ".format(sys.argv[0])) sys.exit() + logging.basicConfig(level=logging.DEBUG) + path0, path1 = sys.argv[1:3] j0 = json.load(open(path0, encoding='utf-8')) @@ -156,4 +62,4 @@ if __name__ == "__main__": equal = compare_jsons(j0, j1) - print("The results are {}equal".format("" if equal else "NOT ")) \ No newline at end of file + print("The city caches are {}equal".format("" if equal else "NOT ")) diff --git a/checkers/compare_json_outputs.py b/checkers/compare_json_outputs.py index b79d141..8ded974 100644 --- a/checkers/compare_json_outputs.py +++ b/checkers/compare_json_outputs.py @@ -12,129 +12,36 @@ import sys import json -from itertools import chain +import logging +from common import compare_stops, compare_transfers, compare_networks def compare_jsons(result0, result1): - - def floats_eq(a, b): - return abs(b - a) < 1e-13 - - def coords_eq(lon1, lat1, lon2, lat2): - return floats_eq(lon1, lon2) and floats_eq(lat1, lat2) - - def osm_id_comparator(el): - return (el['osm_type'], el['osm_id']) + """Compares two objects which are results of subway generation""" network_names0 = sorted([x['network'] for x in result0['networks']]) network_names1 = sorted([x['network'] for x in result1['networks']]) - if network_names0 != network_names1: - print("Different list of network names!") + logging.debug("Different list of network names!") return False - networks0 = sorted(result0['networks'], key=lambda x: x['network']) networks1 = sorted(result1['networks'], key=lambda x: x['network']) - - # Keys to compare routes. 'name' key is omitted since RouteMaster - # can get its name from one of its Routes unpredictably. - route_keys = ('type', 'ref', 'colour', 'route_id') - for network0, network1 in zip(networks0, networks1): - if network0['agency_id'] != network1['agency_id']: - print("Different agency_id:", - network0['network'], network1['network']) + if not compare_networks(network0, network1): return False - route_ids0 = sorted(x['route_id'] for x in network0['routes']) - route_ids1 = sorted(x['route_id'] for x in network1['routes']) - - if route_ids0 != route_ids1: - print("Different route_ids", route_ids0, route_ids1) - return False - - routes0 = sorted(network0['routes'], key=lambda x: x['route_id']) - routes1 = sorted(network1['routes'], key=lambda x: x['route_id']) - - for route0, route1 in zip(routes0, routes1): - route0_props = tuple(route0[k] for k in route_keys) - route1_props = tuple(route1[k] for k in route_keys) - if route0_props != route1_props: - print("Route props of ", route0['route_id'], route1['route_id'], - "are different:", route0_props, route1_props) - return False - - itineraries0 = sorted(route0['itineraries'], - key=lambda x: tuple(chain(*x['stops']))) - itineraries1 = sorted(route1['itineraries'], - key=lambda x: tuple(chain(*x['stops']))) - - for itin0, itin1 in zip(itineraries0, itineraries1): - if itin0['interval'] != itin1['interval']: - print("Different interval:", - itin0['interval'], "!=", itin1['interval'], - "at route", route0['name'], route0['route_id']) - return False - if itin0['stops'] != itin1['stops']: - print("Different stops at route", - route0['name'], route0['route_id']) - return False - stop_ids0 = sorted(x['id'] for x in result0['stops']) stop_ids1 = sorted(x['id'] for x in result1['stops']) if stop_ids0 != stop_ids1: - print("Different stop_ids") + logging.debug("Different stop_ids") return False - stops0 = sorted(result0['stops'], key=lambda x: x['id']) stops1 = sorted(result1['stops'], key=lambda x: x['id']) - for stop0, stop1 in zip(stops0, stops1): - stop0_props = tuple(stop0[k] for k in ('name', 'osm_id', 'osm_type')) - stop1_props = tuple(stop1[k] for k in ('name', 'osm_id', 'osm_type')) - if stop0_props != stop1_props: - print("Different stops properties:", stop0_props, stop1_props) - return False - if not coords_eq(stop0['lon'], stop0['lat'], - stop1['lon'], stop1['lat']): - print("Different stops coordinates:", - stop0_props, stop0['lon'], stop0['lat'], - stop1_props, stop1['lon'], stop1['lat']) + if not compare_stops(stop0, stop1): return False - entrances0 = sorted(stop0['entrances'], key=osm_id_comparator) - entrances1 = sorted(stop1['entrances'], key=osm_id_comparator) - if entrances0 != entrances1: - print("Different stop entrances") - return False - - exits0 = sorted(stop0['exits'], key=osm_id_comparator) - exits1 = sorted(stop1['exits'], key=osm_id_comparator) - if exits0 != exits1: - print("Different stop exits") - return False - - if len(result0['transfers']) != len(result1['transfers']): - print("Different len(transfers):", - len(result0['transfers']), len(result1['transfers'])) - return False - - transfers0 = [tuple(t) if t[0] < t[1] else tuple([t[1], t[0], t[2]]) - for t in result0['transfers']] - transfers1 = [tuple(t) if t[0] < t[1] else tuple([t[1], t[0], t[2]]) - for t in result1['transfers']] - - transfers0.sort(key=lambda x: tuple(x)) - transfers1.sort(key=lambda x: tuple(x)) - - diff_cnt = 0 - for i, (tr0, tr1) in enumerate(zip(transfers0, transfers1)): - if tr0 != tr1: - if i == 0: - print("First pair of different transfers", tr0, tr1) - diff_cnt += 1 - if diff_cnt: - print("Different transfers number = ", diff_cnt) + if not compare_transfers(result0['transfers'], result1['transfers']): return False return True @@ -145,6 +52,8 @@ if __name__ == "__main__": print("Usage: {} ".format(sys.argv[0])) sys.exit() + logging.basicConfig(level=logging.DEBUG) + path0, path1 = sys.argv[1:3] j0 = json.load(open(path0, encoding='utf-8')) @@ -152,4 +61,4 @@ if __name__ == "__main__": equal = compare_jsons(j0, j1) - print("The results are {}equal".format("" if equal else "NOT ")) \ No newline at end of file + print("The results are {}equal".format("" if equal else "NOT "))