From b2a249d837641a5a4f6cefd436164e30d93e7ffd Mon Sep 17 00:00:00 2001 From: Jeff Forbes Date: Fri, 7 Jan 2022 15:58:19 -0500 Subject: [PATCH 1/2] Add sorting of ApiRoute, guaranteeing stable file output. --- stone/frontend/ir_generator.py | 5 +++ stone/ir/api.py | 25 +++++++++++++++ test/test_stone_route_whitelist.py | 49 ++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/stone/frontend/ir_generator.py b/stone/frontend/ir_generator.py index 74c8d967..d6db2272 100644 --- a/stone/frontend/ir_generator.py +++ b/stone/frontend/ir_generator.py @@ -1704,6 +1704,11 @@ def _filter_namespaces_by_route_whitelist(self): namespace.routes = [] namespace.route_by_name = {} namespace.routes_by_name = {} + + # We need a stable sort in order to keep the resultant output + # the same across runs. + routes.sort() + for route in routes: namespace.add_route(route) diff --git a/stone/ir/api.py b/stone/ir/api.py index cc7fb44e..c1df6577 100644 --- a/stone/ir/api.py +++ b/stone/ir/api.py @@ -416,6 +416,31 @@ def name_with_version(self): def __repr__(self): return 'ApiRoute({})'.format(self.name_with_version()) + def _compare(self, lhs, rhs): + if not isinstance(lhs, ApiRoute): + raise TypeError("Expected ApiRoute for object: {}".format(lhs)) + if not isinstance(rhs, ApiRoute): + raise TypeError("Expected ApiRoute for object: {}".format(rhs)) + + if lhs.name < rhs.name or lhs.version < rhs.version: + return -1 + elif lhs.name > rhs.name or lhs.version > rhs.version: + return 1 + else: + return 0 + + def __lt__(self, other): + return self._compare(self, other) < 0 + def __gt__(self, other): + return self._compare(self, other) > 0 + def __eq__(self, other): + return self._compare(self, other) == 0 + def __le__(self, other): + return self._compare(self, other) <= 0 + def __ge__(self, other): + return self._compare(self, other) >= 0 + def __ne__(self, other): + return self._compare(self, other) != 0 class DeprecationInfo(object): diff --git a/test/test_stone_route_whitelist.py b/test/test_stone_route_whitelist.py index 80570120..2408b443 100644 --- a/test/test_stone_route_whitelist.py +++ b/test/test_stone_route_whitelist.py @@ -61,6 +61,55 @@ def test_simple(self): self._compare_namespace_names(api, ['test']) self._compare_datatype_names(api.namespaces['test'], ['TestArg2', 'TestResult2']) + def test_stable_ordering(self): + """ + Tests that route generation returns the same route order on generation. + """ + text = textwrap.dedent("""\ + namespace test + + struct TestArg + f String + "test doc" + example default + f = "asdf" + struct TestResult + f String + "test doc" + example default + f = "asdf" + route TestRoute (TestArg, TestResult, Void) + "test doc" + + route OtherRoute (Void, Void, Void) + "Additional Route" + + """) + + route_whitelist = ["OtherRoute", "TestRoute"] + + for x in range(2,100): + text += textwrap.dedent("""\ + route TestRoute:{} (TestArg, TestResult, Void) + "test doc" + """.format(x)) + route_whitelist.append("TestRoute:{}".format(x)) + + + route_whitelist_filter = { + "route_whitelist": {"test": route_whitelist}, + "datatype_whitelist": {} + } + + api = specs_to_ir([('test.stone', text)], route_whitelist_filter=route_whitelist_filter) + routes = api.namespaces['test'].routes + self.assertEqual(len(routes), 100) + self.assertEqual(routes[0].name, "OtherRoute") + + for x in range(1,100): + self.assertEqual(routes[x].name, "TestRoute") + self.assertEqual(routes[x].version, x) + def test_star(self): """ Tests that inputs with "*" work as expected. From 00c7d6a19867d5a86e9b9d92b6fda14f5b26d142 Mon Sep 17 00:00:00 2001 From: Jeff Forbes Date: Fri, 7 Jan 2022 16:05:39 -0500 Subject: [PATCH 2/2] Lints. --- stone/ir/api.py | 2 +- test/test_stone_route_whitelist.py | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/stone/ir/api.py b/stone/ir/api.py index c1df6577..1b23e182 100644 --- a/stone/ir/api.py +++ b/stone/ir/api.py @@ -421,7 +421,7 @@ def _compare(self, lhs, rhs): raise TypeError("Expected ApiRoute for object: {}".format(lhs)) if not isinstance(rhs, ApiRoute): raise TypeError("Expected ApiRoute for object: {}".format(rhs)) - + if lhs.name < rhs.name or lhs.version < rhs.version: return -1 elif lhs.name > rhs.name or lhs.version > rhs.version: diff --git a/test/test_stone_route_whitelist.py b/test/test_stone_route_whitelist.py index 2408b443..733f3d16 100644 --- a/test/test_stone_route_whitelist.py +++ b/test/test_stone_route_whitelist.py @@ -85,28 +85,27 @@ def test_stable_ordering(self): "Additional Route" """) - + route_whitelist = ["OtherRoute", "TestRoute"] - for x in range(2,100): + for x in range(2, 100): text += textwrap.dedent("""\ route TestRoute:{} (TestArg, TestResult, Void) "test doc" """.format(x)) route_whitelist.append("TestRoute:{}".format(x)) - route_whitelist_filter = { "route_whitelist": {"test": route_whitelist}, "datatype_whitelist": {} } - + api = specs_to_ir([('test.stone', text)], route_whitelist_filter=route_whitelist_filter) routes = api.namespaces['test'].routes self.assertEqual(len(routes), 100) self.assertEqual(routes[0].name, "OtherRoute") - for x in range(1,100): + for x in range(1, 100): self.assertEqual(routes[x].name, "TestRoute") self.assertEqual(routes[x].version, x)