From e07b8e23bd5611c31180fb9e33b68587b6ce2c6e Mon Sep 17 00:00:00 2001 From: Dominik Neise Date: Wed, 26 Jun 2019 14:10:19 +0200 Subject: [PATCH 1/6] auto refactor using: "black -l 127" --- test_replays/test_all.py | 326 +++++++++++++++++++-------------------- 1 file changed, 163 insertions(+), 163 deletions(-) diff --git a/test_replays/test_all.py b/test_replays/test_all.py index 4161a0db..c9b7f968 100644 --- a/test_replays/test_all.py +++ b/test_replays/test_all.py @@ -7,6 +7,7 @@ # Newer unittest features aren't built in for python 2.6 import sys + if sys.version_info[:2] < (2, 7): import unittest2 as unittest else: @@ -24,8 +25,8 @@ sc2reader.log_utils.log_to_console("INFO") -class TestReplays(unittest.TestCase): +class TestReplays(unittest.TestCase): def test_teams(self): replay = sc2reader.load_replay("test_replays/1.2.2.17811/13.SC2Replay") self.assertNotEqual(replay.player[1].team.number, replay.player[2].team.number) @@ -200,7 +201,7 @@ def test_hots_pids(self): "test_replays/2.0.3.24764/Antiga Shipyard (3).SC2Replay", "test_replays/2.0.0.24247/molten.SC2Replay", "test_replays/2.0.0.23925/Akilon Wastes.SC2Replay", - ]: + ]: replay = sc2reader.load_replay(replayfilename) self.assertEqual(replay.expansion, "HotS") @@ -217,8 +218,14 @@ def test_wol_pids(self): def test_hots_hatchfun(self): replay = sc2reader.load_replay("test_replays/2.0.0.24247/molten.SC2Replay") - player_pids = set([ player.pid for player in replay.players]) - spawner_pids = set([ event.player.pid for event in replay.events if "TargetUnitCommandEvent" in event.name and event.ability.name == "SpawnLarva"]) + player_pids = set([player.pid for player in replay.players]) + spawner_pids = set( + [ + event.player.pid + for event in replay.events + if "TargetUnitCommandEvent" in event.name and event.ability.name == "SpawnLarva" + ] + ) self.assertTrue(spawner_pids.issubset(player_pids)) def test_hots_vs_ai(self): @@ -258,20 +265,20 @@ def test_cn_replays(self): def test_unit_types(self): """ sc2reader#136 regression test """ - replay = sc2reader.load_replay('test_replays/2.0.8.25604/issue136.SC2Replay') - hellion_times = [u.started_at for u in replay.players[0].units if u.name == 'Hellion'] - hellbat_times = [u.started_at for u in replay.players[0].units if u.name == 'BattleHellion'] + replay = sc2reader.load_replay("test_replays/2.0.8.25604/issue136.SC2Replay") + hellion_times = [u.started_at for u in replay.players[0].units if u.name == "Hellion"] + hellbat_times = [u.started_at for u in replay.players[0].units if u.name == "BattleHellion"] self.assertEqual(hellion_times, [5180, 5183]) self.assertEqual(hellbat_times, [6736, 6741, 7215, 7220, 12004, 12038]) @unittest.expectedFailure def test_outmatched_pids(self): - replay = sc2reader.load_replay('test_replays/2.0.8.25604/issue131_arid_wastes.SC2Replay') + replay = sc2reader.load_replay("test_replays/2.0.8.25604/issue131_arid_wastes.SC2Replay") self.assertEqual(replay.players[0].pid, 1) self.assertEqual(replay.players[1].pid, 3) self.assertEqual(replay.players[2].pid, 4) - replay = sc2reader.load_replay('test_replays/2.0.8.25604/issue135.SC2Replay') + replay = sc2reader.load_replay("test_replays/2.0.8.25604/issue135.SC2Replay") self.assertEqual(replay.players[0].pid, 1) self.assertEqual(replay.players[1].pid, 2) self.assertEqual(replay.players[2].pid, 4) @@ -285,8 +292,8 @@ def test_outmatched_pids(self): @unittest.expectedFailure def test_map_info(self): replay = sc2reader.load_replay("test_replays/1.5.3.23260/ggtracker_109233.SC2Replay", load_map=True) - self.assertEqual(replay.map.map_info.tile_set, 'Avernus') - self.assertEqual(replay.map.map_info.fog_type, 'Dark') + self.assertEqual(replay.map.map_info.tile_set, "Avernus") + self.assertEqual(replay.map.map_info.fog_type, "Dark") self.assertEqual(replay.map.map_info.width, 176) self.assertEqual(replay.map.map_info.height, 160) self.assertEqual(replay.map.map_info.camera_top, 134) @@ -301,14 +308,10 @@ def test_engine_plugins(self): replay = sc2reader.load_replay( "test_replays/2.0.5.25092/cn1.SC2Replay", - engine=sc2reader.engine.GameEngine(plugins=[ - ContextLoader(), - APMTracker(), - SelectionTracker(), - ]) + engine=sc2reader.engine.GameEngine(plugins=[ContextLoader(), APMTracker(), SelectionTracker()]), ) - code, details = replay.plugins['ContextLoader'] + code, details = replay.plugins["ContextLoader"] self.assertEqual(code, 0) self.assertEqual(details, dict()) @@ -336,71 +339,77 @@ def test_factory_plugins(self): def test_gameheartnormalizer_plugin(self): from sc2reader.engine.plugins import GameHeartNormalizer + sc2reader.engine.register_plugin(GameHeartNormalizer()) # Not a GameHeart game! replay = sc2reader.load_replay("test_replays/2.0.0.24247/molten.SC2Replay") - player_pids = set([ player.pid for player in replay.players]) - spawner_pids = set([ event.player.pid for event in replay.events if "TargetUnitCommandEvent" in event.name and event.ability.name == "SpawnLarva"]) + player_pids = set([player.pid for player in replay.players]) + spawner_pids = set( + [ + event.player.pid + for event in replay.events + if "TargetUnitCommandEvent" in event.name and event.ability.name == "SpawnLarva" + ] + ) self.assertTrue(spawner_pids.issubset(player_pids)) replay = sc2reader.load_replay("test_replays/gameheart/gameheart.SC2Replay") self.assertEqual(replay.events[0].frame, 0) self.assertEqual(replay.game_length.seconds, 636) self.assertEqual(len(replay.observers), 5) - self.assertEqual(replay.players[0].name, 'SjoWBBII') - self.assertEqual(replay.players[0].play_race, 'Terran') - self.assertEqual(replay.players[1].name, 'Stardust') - self.assertEqual(replay.players[1].play_race, 'Protoss') + self.assertEqual(replay.players[0].name, "SjoWBBII") + self.assertEqual(replay.players[0].play_race, "Terran") + self.assertEqual(replay.players[1].name, "Stardust") + self.assertEqual(replay.players[1].play_race, "Protoss") self.assertEqual(len(replay.teams), 2) - self.assertEqual(replay.teams[0].players[0].name, 'SjoWBBII') - self.assertEqual(replay.teams[1].players[0].name, 'Stardust') + self.assertEqual(replay.teams[0].players[0].name, "SjoWBBII") + self.assertEqual(replay.teams[1].players[0].name, "Stardust") self.assertEqual(replay.winner, replay.teams[1]) replay = sc2reader.load_replay("test_replays/gameheart/gh_sameteam.SC2Replay") self.assertEqual(replay.events[0].frame, 0) self.assertEqual(replay.game_length.seconds, 424) self.assertEqual(len(replay.observers), 5) - self.assertEqual(replay.players[0].name, 'EGJDRC') - self.assertEqual(replay.players[0].play_race, 'Zerg') - self.assertEqual(replay.players[1].name, 'LiquidTaeJa') - self.assertEqual(replay.players[1].play_race, 'Terran') + self.assertEqual(replay.players[0].name, "EGJDRC") + self.assertEqual(replay.players[0].play_race, "Zerg") + self.assertEqual(replay.players[1].name, "LiquidTaeJa") + self.assertEqual(replay.players[1].play_race, "Terran") self.assertEqual(len(replay.teams), 2) - self.assertEqual(replay.teams[0].players[0].name, 'EGJDRC') - self.assertEqual(replay.teams[1].players[0].name, 'LiquidTaeJa') + self.assertEqual(replay.teams[0].players[0].name, "EGJDRC") + self.assertEqual(replay.teams[1].players[0].name, "LiquidTaeJa") self.assertEqual(replay.winner, replay.teams[0]) def test_replay_event_order(self): replay = sc2reader.load_replay("test_replays/event_order.SC2Replay") def test_creepTracker(self): - from sc2reader.engine.plugins import CreepTracker - - for replayfilename in [ - "test_replays/2.0.8.25605/ggtracker_3621322.SC2Replay", - "test_replays/2.0.8.25605/ggtracker_3621402.SC2Replay", - "test_replays/2.0.8.25605/ggtracker_3663861.SC2Replay", - "test_replays/2.0.8.25605/ggtracker_3695400.SC2Replay", - "test_replays/3.1.2/6494799.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - pluginEngine=sc2reader.engine.GameEngine(plugins=[ - CreepTracker() - ]) - replay =factory.load_replay(replayfilename,engine=pluginEngine,load_map= True,load_level=4) - - for player_id in replay.player: - if replay.player[player_id].play_race == "Zerg": - assert replay.player[player_id].max_creep_spread[1] >0 - assert replay.player[player_id].creep_spread_by_minute[0] >0 -# print("MCS", replay.player[player_id].max_creep_spread) -# print("CSBM", replay.player[player_id].creep_spread_by_minute) + from sc2reader.engine.plugins import CreepTracker - - replay =factory.load_replay("test_replays/2.0.8.25605/ggtracker_3621402.SC2Replay",load_map= True,engine=pluginEngine,load_level=4) - assert replay.player[2].max_creep_spread == (840,24.83) - assert replay.player[2].creep_spread_by_minute[420] == 9.4 - assert replay.player[2].creep_spread_by_minute[780] == 22.42 + for replayfilename in [ + "test_replays/2.0.8.25605/ggtracker_3621322.SC2Replay", + "test_replays/2.0.8.25605/ggtracker_3621402.SC2Replay", + "test_replays/2.0.8.25605/ggtracker_3663861.SC2Replay", + "test_replays/2.0.8.25605/ggtracker_3695400.SC2Replay", + "test_replays/3.1.2/6494799.SC2Replay", + ]: + factory = sc2reader.factories.SC2Factory() + pluginEngine = sc2reader.engine.GameEngine(plugins=[CreepTracker()]) + replay = factory.load_replay(replayfilename, engine=pluginEngine, load_map=True, load_level=4) + + for player_id in replay.player: + if replay.player[player_id].play_race == "Zerg": + assert replay.player[player_id].max_creep_spread[1] > 0 + assert replay.player[player_id].creep_spread_by_minute[0] > 0 + # print("MCS", replay.player[player_id].max_creep_spread) + # print("CSBM", replay.player[player_id].creep_spread_by_minute) + + replay = factory.load_replay( + "test_replays/2.0.8.25605/ggtracker_3621402.SC2Replay", load_map=True, engine=pluginEngine, load_level=4 + ) + assert replay.player[2].max_creep_spread == (840, 24.83) + assert replay.player[2].creep_spread_by_minute[420] == 9.4 + assert replay.player[2].creep_spread_by_minute[780] == 22.42 def test_bad_unit_ids(self): with self.assertRaises(CorruptTrackerFileError): @@ -415,56 +424,47 @@ def test_reloaded(self): replay = sc2reader.load_replay("test_replays/2.1.3.28667/Habitation Station LE (54).SC2Replay") def test_214(self): - replay = sc2reader.load_replay("test_replays/2.1.4/Catallena LE.SC2Replay", load_level=4) + replay = sc2reader.load_replay("test_replays/2.1.4/Catallena LE.SC2Replay", load_level=4) def test_lotv1(self): - replay = sc2reader.load_replay("test_replays/lotv/lotv1.SC2Replay") - self.assertEqual(replay.expansion, "LotV") - replay = sc2reader.load_replay("test_replays/lotv/lotv2.SC2Replay") - self.assertEqual(replay.expansion, "LotV") - + replay = sc2reader.load_replay("test_replays/lotv/lotv1.SC2Replay") + self.assertEqual(replay.expansion, "LotV") + replay = sc2reader.load_replay("test_replays/lotv/lotv2.SC2Replay") + self.assertEqual(replay.expansion, "LotV") def test_lotv_creepTracker(self): - from sc2reader.engine.plugins import CreepTracker + from sc2reader.engine.plugins import CreepTracker - for replayfilename in [ - "test_replays/lotv/lotv1.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - pluginEngine=sc2reader.engine.GameEngine(plugins=[ - CreepTracker() - ]) - replay =factory.load_replay(replayfilename,engine=pluginEngine,load_map= True) + for replayfilename in ["test_replays/lotv/lotv1.SC2Replay"]: + factory = sc2reader.factories.SC2Factory() + pluginEngine = sc2reader.engine.GameEngine(plugins=[CreepTracker()]) + replay = factory.load_replay(replayfilename, engine=pluginEngine, load_map=True) - for player_id in replay.player: - if replay.player[player_id].play_race == "Zerg": - assert replay.player[player_id].max_creep_spread != 0 - assert replay.player[player_id].creep_spread_by_minute + for player_id in replay.player: + if replay.player[player_id].play_race == "Zerg": + assert replay.player[player_id].max_creep_spread != 0 + assert replay.player[player_id].creep_spread_by_minute def test_lotv_map(self): - # This test currently fails in decoders.py with 'TypeError: ord() expected a character, but string of length 0 found' - for replayfilename in [ - "test_replays/lotv/lotv1.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - replay =factory.load_replay(replayfilename,load_level=1,load_map= True) + # This test currently fails in decoders.py with 'TypeError: ord() expected a character, but string of length 0 found' + for replayfilename in ["test_replays/lotv/lotv1.SC2Replay"]: + factory = sc2reader.factories.SC2Factory() + replay = factory.load_replay(replayfilename, load_level=1, load_map=True) def test_30(self): - replay = sc2reader.load_replay("test_replays/3.0.0.38215/first.SC2Replay") - replay = sc2reader.load_replay("test_replays/3.0.0.38215/second.SC2Replay") - replay = sc2reader.load_replay("test_replays/3.0.0.38215/third.SC2Replay") + replay = sc2reader.load_replay("test_replays/3.0.0.38215/first.SC2Replay") + replay = sc2reader.load_replay("test_replays/3.0.0.38215/second.SC2Replay") + replay = sc2reader.load_replay("test_replays/3.0.0.38215/third.SC2Replay") def test_31(self): - for i in range(1,5): - print("DOING {}".format(i)) - replay = sc2reader.load_replay("test_replays/3.1.0/{}.SC2Replay".format(i)) + for i in range(1, 5): + print("DOING {}".format(i)) + replay = sc2reader.load_replay("test_replays/3.1.0/{}.SC2Replay".format(i)) def test_30_map(self): - for replayfilename in [ - "test_replays/3.0.0.38215/third.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - replay =factory.load_replay(replayfilename,load_level=1,load_map= True) + for replayfilename in ["test_replays/3.0.0.38215/third.SC2Replay"]: + factory = sc2reader.factories.SC2Factory() + replay = factory.load_replay(replayfilename, load_level=1, load_map=True) def test_30_apms(self): from sc2reader.factories.plugins.replay import APMTracker, SelectionTracker, toJSON @@ -473,60 +473,68 @@ def test_30_apms(self): factory.register_plugin("Replay", APMTracker()) replay = factory.load_replay("test_replays/3.0.0.38215/fourth.SC2Replay") for player in replay.players: - if player.name == 'Owl': + if player.name == "Owl": print(player.name, player.avg_apm) self.assertTrue(player.avg_apm > 110) def test_38749(self): replay = sc2reader.load_replay("test_replays/3.0.0.38749/1.SC2Replay") - self.assertEqual(replay.expansion, 'HotS') + self.assertEqual(replay.expansion, "HotS") replay = sc2reader.load_replay("test_replays/3.0.0.38749/2.SC2Replay") - self.assertEqual(replay.expansion, 'HotS') + self.assertEqual(replay.expansion, "HotS") def test_38996(self): replay = sc2reader.load_replay("test_replays/3.0.0.38996/1.SC2Replay") - self.assertEqual(replay.expansion, 'LotV') + self.assertEqual(replay.expansion, "LotV") replay = sc2reader.load_replay("test_replays/3.0.0.38996/2.SC2Replay") - self.assertEqual(replay.expansion, 'LotV') + self.assertEqual(replay.expansion, "LotV") def test_funny_minerals(self): replay = sc2reader.load_replay("test_replays/3.1.0/centralprotocol.SC2Replay") replay.load_map() - xmldoc = minidom.parseString(replay.map.archive.read_file('Objects')) - itemlist = xmldoc.getElementsByTagName('ObjectUnit') - mineralPosStrs = [ou.attributes['Position'].value for ou in itemlist if 'MineralField' in ou.attributes['UnitType'].value] - mineralFieldNames = list(set([ou.attributes['UnitType'].value for ou in itemlist if 'MineralField' in ou.attributes['UnitType'].value])) + xmldoc = minidom.parseString(replay.map.archive.read_file("Objects")) + itemlist = xmldoc.getElementsByTagName("ObjectUnit") + mineralPosStrs = [ + ou.attributes["Position"].value for ou in itemlist if "MineralField" in ou.attributes["UnitType"].value + ] + mineralFieldNames = list( + set([ou.attributes["UnitType"].value for ou in itemlist if "MineralField" in ou.attributes["UnitType"].value]) + ) # print(mineralFieldNames) self.assertTrue(len(mineralPosStrs) > 0) def test_dusk(self): replay = sc2reader.load_replay("test_replays/3.1.0/dusktowers.SC2Replay") - self.assertEqual(replay.expansion, 'LotV') + self.assertEqual(replay.expansion, "LotV") def test_32(self): replay = sc2reader.load_replay("test_replays/3.2.0/1.SC2Replay") self.assertTrue(replay is not None) def test_33(self): - for replaynum in range(1,4): + for replaynum in range(1, 4): replay = sc2reader.load_replay("test_replays/3.3.0/{}.SC2Replay".format(replaynum)) self.assertTrue(replay is not None) def test_33_shift_click_calldown_mule(self): replay = sc2reader.load_replay("test_replays/3.3.0/ggissue48.SC2Replay") + def efilter(e): return hasattr(e, "ability") and e.ability_name == "CalldownMULE" + self.assertEqual(len(list(filter(efilter, replay.events))), 29) def test_33_shift_click_spawn_larva(self): replay = sc2reader.load_replay("test_replays/3.3.0/ggissue49.SC2Replay") + def efilter(e): return hasattr(e, "ability") and e.ability_name == "SpawnLarva" + self.assertEqual(len(list(filter(efilter, replay.events))), 23) def test_34(self): replay = sc2reader.load_replay("test_replays/3.4.0/issueYY.SC2Replay") - self.assertEqual(replay.expansion, 'LotV') + self.assertEqual(replay.expansion, "LotV") def test_lotv_time(self): replay = sc2reader.load_replay("test_replays/lotv/lotv1.SC2Replay") @@ -538,56 +546,44 @@ def test_37(self): replay = sc2reader.load_replay("test_replays/3.7.0/2.SC2Replay") def test_312(self): - for replayfilename in [ - "test_replays/3.12/Honorgrounds.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - replay =factory.load_replay(replayfilename,load_level=0) - replay =factory.load_replay(replayfilename,load_level=1) + for replayfilename in ["test_replays/3.12/Honorgrounds.SC2Replay"]: + factory = sc2reader.factories.SC2Factory() + replay = factory.load_replay(replayfilename, load_level=0) + replay = factory.load_replay(replayfilename, load_level=1) def test_316(self): - for replayfilename in [ - "test_replays/3.16/AbyssalReef.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - replay =factory.load_replay(replayfilename) + for replayfilename in ["test_replays/3.16/AbyssalReef.SC2Replay"]: + factory = sc2reader.factories.SC2Factory() + replay = factory.load_replay(replayfilename) def test_54518(self): - for replayfilename in [ - "test_replays/3.14.0.54518/1.SC2Replay", - "test_replays/3.14.0.54518/2.SC2Replay", - "test_replays/3.14.0.54518/3.SC2Replay", + for replayfilename in [ + "test_replays/3.14.0.54518/1.SC2Replay", + "test_replays/3.14.0.54518/2.SC2Replay", + "test_replays/3.14.0.54518/3.SC2Replay", ]: - factory = sc2reader.factories.SC2Factory() - replay =factory.load_replay(replayfilename) + factory = sc2reader.factories.SC2Factory() + replay = factory.load_replay(replayfilename) def test_59587(self): - for replayfilename in [ - "test_replays/4.0.0.59587/1.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - replay = factory.load_replay(replayfilename) + for replayfilename in ["test_replays/4.0.0.59587/1.SC2Replay"]: + factory = sc2reader.factories.SC2Factory() + replay = factory.load_replay(replayfilename) def test_64469(self): - for replayfilename in [ - "test_replays/4.3.0.64469/1.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - replay = factory.load_replay(replayfilename) + for replayfilename in ["test_replays/4.3.0.64469/1.SC2Replay"]: + factory = sc2reader.factories.SC2Factory() + replay = factory.load_replay(replayfilename) def test_coop(self): - for replayfilename in [ - "test_replays/coop/CoA.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - replay = factory.load_replay(replayfilename) + for replayfilename in ["test_replays/coop/CoA.SC2Replay"]: + factory = sc2reader.factories.SC2Factory() + replay = factory.load_replay(replayfilename) def test_65895(self): - for replayfilename in [ - "test_replays/4.4.0.65895/1.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - replay = factory.load_replay(replayfilename) + for replayfilename in ["test_replays/4.4.0.65895/1.SC2Replay"]: + factory = sc2reader.factories.SC2Factory() + replay = factory.load_replay(replayfilename) def test_event_print(self): replay = sc2reader.load_replay("test_replays/lotv/lotv1.SC2Replay") @@ -599,11 +595,9 @@ def test_event_print(self): capturedOutput.close() def test_70154(self): - for replayfilename in [ - "test_replays/4.7.0.70154/1.SC2Replay", - ]: - factory = sc2reader.factories.SC2Factory() - replay = factory.load_replay(replayfilename) + for replayfilename in ["test_replays/4.7.0.70154/1.SC2Replay"]: + factory = sc2reader.factories.SC2Factory() + replay = factory.load_replay(replayfilename) def test_anonymous_replay(self): replayfilename = "test_replays/4.1.2.60604/1.SC2Replay" @@ -641,33 +635,37 @@ def test_game_event_string(self): event.player = player self.assertEqual("{0}\tPlayer {1} - ({2}) ".format(time, player.pid, player.play_race), event._str_prefix()) + class TestGameEngine(unittest.TestCase): class TestEvent(object): - name='TestEvent' + name = "TestEvent" + def __init__(self, value): self.value = value + def __str__(self): return self.value class TestPlugin1(object): - name = 'TestPlugin1' + name = "TestPlugin1" def handleInitGame(self, event, replay): - yield TestGameEngine.TestEvent('b') - yield TestGameEngine.TestEvent('c') + yield TestGameEngine.TestEvent("b") + yield TestGameEngine.TestEvent("c") def handleTestEvent(self, event, replay): print("morestuff") - if event.value == 'd': + if event.value == "d": yield sc2reader.engine.PluginExit(self, code=1, details=dict(msg="Fail!")) else: - yield TestGameEngine.TestEvent('d') + yield TestGameEngine.TestEvent("d") def handleEndGame(self, event, replay): - yield TestGameEngine.TestEvent('g') + yield TestGameEngine.TestEvent("g") class TestPlugin2(object): - name = 'TestPlugin2' + name = "TestPlugin2" + def handleInitGame(self, event, replay): replay.engine_events = list() @@ -675,10 +673,10 @@ def handleTestEvent(self, event, replay): replay.engine_events.append(event) def handlePluginExit(self, event, replay): - yield TestGameEngine.TestEvent('e') + yield TestGameEngine.TestEvent("e") def handleEndGame(self, event, replay): - yield TestGameEngine.TestEvent('f') + yield TestGameEngine.TestEvent("f") class MockReplay(object): def __init__(self, events): @@ -688,12 +686,13 @@ def test_plugin1(self): engine = sc2reader.engine.GameEngine() engine.register_plugin(self.TestPlugin1()) engine.register_plugin(self.TestPlugin2()) - replay = self.MockReplay([self.TestEvent('a')]) + replay = self.MockReplay([self.TestEvent("a")]) engine.run(replay) - self.assertEqual(''.join(str(e) for e in replay.engine_events), 'bdecaf') - self.assertEqual(replay.plugin_failures, ['TestPlugin1']) - self.assertEqual(replay.plugin_result['TestPlugin1'], (1, dict(msg="Fail!"))) - self.assertEqual(replay.plugin_result['TestPlugin2'], (0, dict())) + self.assertEqual("".join(str(e) for e in replay.engine_events), "bdecaf") + self.assertEqual(replay.plugin_failures, ["TestPlugin1"]) + self.assertEqual(replay.plugin_result["TestPlugin1"], (1, dict(msg="Fail!"))) + self.assertEqual(replay.plugin_result["TestPlugin2"], (0, dict())) + class MockPlayer(object): def __init__(self): @@ -701,5 +700,6 @@ def __init__(self): self.play_race = None self.pid = None -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() From 0f3726f537ecedf952ef8fc5d7f846c76abc8115 Mon Sep 17 00:00:00 2001 From: Dominik Neise Date: Wed, 26 Jun 2019 14:14:09 +0200 Subject: [PATCH 2/6] this print does not help anybody, but the original author ... --- test_replays/test_all.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test_replays/test_all.py b/test_replays/test_all.py index c9b7f968..452b4543 100644 --- a/test_replays/test_all.py +++ b/test_replays/test_all.py @@ -654,7 +654,6 @@ def handleInitGame(self, event, replay): yield TestGameEngine.TestEvent("c") def handleTestEvent(self, event, replay): - print("morestuff") if event.value == "d": yield sc2reader.engine.PluginExit(self, code=1, details=dict(msg="Fail!")) else: From a403034cb30fd97b5e7b5b02a106adcf2b29e467 Mon Sep 17 00:00:00 2001 From: Dominik Neise Date: Wed, 26 Jun 2019 15:30:00 +0200 Subject: [PATCH 3/6] use a different replay for some lotv tests: - make sure there is really a zerg in that replay, otherwise the test would test nothing at all - remove outdated comment, that test does not fail. --- test_replays/test_all.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test_replays/test_all.py b/test_replays/test_all.py index 452b4543..f974aaf2 100644 --- a/test_replays/test_all.py +++ b/test_replays/test_all.py @@ -435,19 +435,21 @@ def test_lotv1(self): def test_lotv_creepTracker(self): from sc2reader.engine.plugins import CreepTracker - for replayfilename in ["test_replays/lotv/lotv1.SC2Replay"]: + for replayfilename in ["test_replays/4.0.0.59587/1.SC2Replay"]: factory = sc2reader.factories.SC2Factory() pluginEngine = sc2reader.engine.GameEngine(plugins=[CreepTracker()]) replay = factory.load_replay(replayfilename, engine=pluginEngine, load_map=True) + is_at_least_one_zerg_in_game = False for player_id in replay.player: if replay.player[player_id].play_race == "Zerg": + is_at_least_one_zerg_in_game = True assert replay.player[player_id].max_creep_spread != 0 assert replay.player[player_id].creep_spread_by_minute + assert is_at_least_one_zerg_in_game def test_lotv_map(self): - # This test currently fails in decoders.py with 'TypeError: ord() expected a character, but string of length 0 found' - for replayfilename in ["test_replays/lotv/lotv1.SC2Replay"]: + for replayfilename in ["test_replays/4.0.0.59587/1.SC2Replay"]: factory = sc2reader.factories.SC2Factory() replay = factory.load_replay(replayfilename, load_level=1, load_map=True) From 2b1fc8430f8b1be7842687581ceb4d9f22905600 Mon Sep 17 00:00:00 2001 From: Dominik Neise Date: Wed, 26 Jun 2019 15:53:46 +0200 Subject: [PATCH 4/6] let's remove the s2gs tests for a moment in order to see if the replay tests work --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1370bc61..7e51e473 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ my-steps: &steps # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - run: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics #- run: pytest # test_s2gs test_replays - - run: python -m unittest discover test_s2gs + # - run: python -m unittest discover test_s2gs - run: python -m unittest discover test_replays jobs: From 0c875260d11e4c07419448d48635c2507822eac9 Mon Sep 17 00:00:00 2001 From: Dominik Neise Date: Wed, 26 Jun 2019 15:59:32 +0200 Subject: [PATCH 5/6] run s2gs test again --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7e51e473..1370bc61 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ my-steps: &steps # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - run: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics #- run: pytest # test_s2gs test_replays - # - run: python -m unittest discover test_s2gs + - run: python -m unittest discover test_s2gs - run: python -m unittest discover test_replays jobs: From 57c7064446c03a2c576bd3cfe73f0dd0595de2b4 Mon Sep 17 00:00:00 2001 From: Dominik Neise Date: Wed, 26 Jun 2019 16:35:46 +0200 Subject: [PATCH 6/6] replace a HotS summary with a LotV summary ... --- test_s2gs/lotv.s2gs | Bin 0 -> 30667 bytes test_s2gs/test_all.py | 10 ++++++---- 2 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 test_s2gs/lotv.s2gs diff --git a/test_s2gs/lotv.s2gs b/test_s2gs/lotv.s2gs new file mode 100644 index 0000000000000000000000000000000000000000..1324259498a75792f3cef8511a9a6ae1458c4020 GIT binary patch literal 30667 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�Yn~7 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