Create attractive VASL scenarios, with loads of useful information embedded to assist with game play. https://vasl-templates.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
vasl-templates/vasl_templates/webapp/tests/test_national_capabilities.py

323 lines
12 KiB

""" Test National Capabilities snippet generation. """
import os
import shutil
import io
import lxml.html
from vasl_templates.webapp.tests.utils import init_webapp, get_nationalities, SwitchFrame
# ---------------------------------------------------------------------
def test_national_capabilities_reports( webapp, webdriver ):
"""Check the national capabilities reports."""
# initialize
webapp.control_tests.set_data_dir( "{REAL}" )
init_webapp( webapp, webdriver )
# initialize
check_dir = os.path.join( os.path.split(__file__)[0], "fixtures/nat-caps/" )
save_dir = os.environ.get( "NATCAPS_SAVEDIR" ) # nb: define this to save the generated reports
if save_dir and os.path.isdir(save_dir):
shutil.rmtree( save_dir )
def do_test( nats, theater, years ): #pylint: disable=missing-docstring
# initialize
failed = False
# check each nationality
for nat in nats:
# check each year
for year in range( years[0], years[1]+1 ):
# get the next snippet
nat_caps = _get_nat_caps( webapp, webdriver, nat, theater, year, 1 )
if nat in ("filipino",):
assert nat_caps is None
continue
report = _make_report( nat, theater, year, nat_caps )
# check if we should save the report
fname = os.path.join(
os.path.join("kfw",nat) if theater == "Korea" else nat,
"{}.txt".format( year )
)
if save_dir:
fname2 = os.path.join( save_dir, fname )
os.makedirs( os.path.split(fname2)[0], exist_ok=True )
with open( os.path.join(save_dir,fname2), "w", encoding="utf-8" ) as fp:
fp.write( report )
# check the report
fname = os.path.join( check_dir, fname )
with open( fname, "r", encoding="utf-8" ) as fp:
if fp.read() != report:
if save_dir:
print( "FAILED:", fname )
failed = True
else:
assert False, "Report mismatch: {}".format( fname )
assert not failed
# check each nationality
nationalities = list( get_nationalities( webapp ).keys() )
do_test(
[ nat for nat in nationalities if not nat.startswith("kfw-") ],
"ETO", (1940,1945)
)
do_test(
[ "american", "kfw-rok", "british", "kfw-ounc", "kfw-kpa", "kfw-cpva" ],
"Korea", (1950,1953)
)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def _get_nat_caps( webapp, webdriver, nat, theater, year, month ): #pylint: disable=too-many-locals
"""Get a national capabilities snippet."""
# get the snippet
url = webapp.url_for( "get_national_capabilities", nat=nat, theater=theater, year=year, month=month )
webdriver.get( url )
with SwitchFrame( webdriver, "#results" ):
buf = webdriver.page_source
# check if there is anything
if "Not available." in buf:
return None
def to_text( elem ):
"""Convert an HTML element to text (tags are stripped, we don't descend into child nodes)."""
vals = [ elem.text ]
for c in elem.iterchildren():
if c.tag == "ul":
continue
vals.extend( [ c.text, c.tail ] )
vals.append( elem.tail )
vals = [ v for v in vals if v ]
return "".join( vals )
# parse the basic details
report = {}
doc = lxml.html.fromstring( buf )
fields = [ "grenades", "hob-drm", "th-color", "oba-black", "oba-red", "oba-access" ]
for field in fields:
elems = doc.xpath( "//*[@class='{}']".format( field ) )
if len(elems) == 0:
report[ field ] = "-"
else:
assert len(elems) == 1
report[ field ] = to_text( elems[0] ).strip()
if report["hob-drm"] != "-":
assert report["hob-drm"].startswith( "Heat of Battle: " )
report["hob-drm"] = report["hob-drm"][16:]
# parse the OBA comments
report["oba-comments"] = []
for elem in doc.xpath( "//ul[@class='oba-comments']/li" ):
report["oba-comments"].append( elem.text.strip() )
def parse_list( root, items, depth ):
"""Parse a list of items (and their child items)."""
for elem in root.xpath( "./li" ):
val = to_text( elem )
val = val.strip()
elems = elem.xpath( "./ul" )
if not elems:
items.append( val )
else:
assert len(elems) == 1
children = []
parse_list( elems[0], children, depth+1 )
items.append( [ val, children ] )
# parse the notes
report["notes"] = []
elems = doc.xpath( "//ul[@class='notes']" )
if len(elems) == 0:
pass
else:
assert len(elems) == 1
parse_list( elems[0], report["notes"], 0 )
return report
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def _make_report( nat, theater, year, nat_caps ):
"""Generate a report for the national capabilities."""
def dump_list_items( items, depth ):
"""Dump a list of items (and their child items)."""
tab = " " * depth
for item in items:
if isinstance( item, str ):
print( "{}* {}".format( tab, item ), file=buf )
else:
assert isinstance( item, list ) and len(item) == 2
print( "{}* {}".format( tab, item[0] ), file=buf )
dump_list_items( item[1], depth+1 )
# generate the report
buf = io.StringIO()
print( "=== {} ({} {}) ===".format( nat, theater, year ), file=buf )
print( "", file=buf )
print( nat_caps["grenades"], file=buf )
print( "HoB: {}".format( nat_caps["hob-drm"] ), file=buf )
print( nat_caps["th-color"], file=buf )
print( "OBA: {} {}".format( nat_caps["oba-black"], nat_caps["oba-red"] ), end="", file=buf )
if nat_caps["oba-access"]:
print( " {}".format( nat_caps["oba-access"] ), end="", file=buf )
print( "", file=buf )
for cmt in nat_caps["oba-comments"]:
print( "- {}".format( cmt ), file=buf )
if nat_caps["notes"]:
print( "", file=buf )
dump_list_items( nat_caps["notes"], 0 )
return buf.getvalue()
# ---------------------------------------------------------------------
def test_time_based_national_capabilities( webapp, webdriver ):
"""Check time-based national capabilities.
Capabilities that change according to the year are checked in the reports,
these tests check those capabilities that change in the middle of a year.
"""
# initialize
webapp.control_tests.set_data_dir( "{REAL}" )
init_webapp( webapp, webdriver )
def check_notes( nat, theater, month, year, expected ):
"""Check the national capabilities notes."""
nat_caps = _get_nat_caps( webapp, webdriver, nat, theater, year, month )
for e in expected:
notes = [
n if isinstance(n,str) else n[0]
for n in nat_caps["notes"]
]
if e.startswith( "!" ):
assert e[1:] not in notes
else:
assert e in notes
def check_oba( nat, theater, month, year, expected_black, expected_red, comments=None, plentiful=None ):
"""Check the OBA national capabilities."""
nat_caps = _get_nat_caps( webapp, webdriver, nat, theater, year, month )
assert nat_caps["oba-black"] == expected_black
assert nat_caps["oba-red"] == expected_red
if plentiful:
assert comments is None
comments = [ "Plentiful Ammo included" ]
if comments:
assert nat_caps["oba-comments"] == comments
else:
assert not nat_caps["oba-comments"]
def check_th_color( nat, theater, month, year, expected ):
"""Check the TH# color."""
nat_caps = _get_nat_caps( webapp, webdriver, nat, theater, year, month )
assert nat_caps["th-color"] == expected
# test the German national capabilities
check_notes( "german", "ETO", 12, 1942, [
"No Inherent PF", "No Inherent ATMM"
] )
check_notes( "german", "ETO", 9, 1943, [
"No Inherent PF", "No Inherent ATMM"
] )
check_notes( "german", "ETO", 10, 1943, [
"Inherent PF", "No Inherent ATMM"
] )
# test the Russian national capabilities
check_notes( "russian", "ETO", 12, 1941, [
"Commissars", "Riders NA"
] )
check_notes( "russian", "ETO", 10, 1942, [
"Commissars", "Riders OK"
] )
check_notes( "russian", "ETO", 11, 1942, [
"Commissars NA", "Riders OK"
] )
check_notes( "russian", "ETO", 1, 1943, [
"Commissars NA", "Riders OK"
] )
# test the Finnish national capabilities
# NOTE: We should test for Inherent PF here, but it's in a nested sub-list (more trouble than it's worth).
check_oba( "finnish", "ETO", 12, 1943, "8B", "3R", plentiful=True )
check_oba( "finnish", "ETO", 1, 1944, "8B", "3R", plentiful=True )
check_oba( "finnish", "ETO", 9, 1944, "8B", "3R", plentiful=True )
check_oba( "finnish", "ETO", 10, 1944, "7B", "3R", plentiful=True )
check_oba( "finnish", "ETO", 1, 1945, "7B", "3R", plentiful=True )
# test the Axis Minor national capabilities
check_notes( "romanian", "ETO", 12, 1942, [
"No Inherent ATMM"
] )
check_notes( "romanian", "ETO", 6, 1943, [
"No Inherent ATMM"
] )
check_notes( "romanian", "ETO", 7, 1943, [
"Inherent ATMM in Romanian non-Crew Elite & 1st Line MMC (-2 CC DRM)"
] )
check_notes( "romanian", "ETO", 1, 1944, [
"Inherent ATMM in Romanian non-Crew Elite & 1st Line MMC (-2 CC DRM)"
] )
# test the KFW American national Capabilities
# NOTE: We should test for early war Katusa here, but it's in a nested sub-list (more trouble than it's worth).
check_oba( "american", "Korea", 12, 1949, "???", "3R" )
check_oba( "american", "Korea", 5, 1950, "???", "3R" )
check_oba( "american", "Korea", 6, 1950, "9B", "3R" )
check_oba( "american", "Korea", 8, 1950, "9B", "3R" )
check_oba( "american", "Korea", 9, 1950, "10B", "3R", plentiful=True )
check_oba( "american", "Korea", 1, 1951, "10B", "3R", plentiful=True )
check_th_color( "american", "Korea", 12, 1949, "??? TH#" )
check_th_color( "american", "Korea", 5, 1950, "??? TH#" )
check_th_color( "american", "Korea", 6, 1950, "Red TH#" )
check_th_color( "american", "Korea", 8, 1950, "Red TH#" )
check_th_color( "american", "Korea", 9, 1950, "Black TH#" )
check_th_color( "american", "Korea", 1, 1951, "Black TH#" )
check_notes( "american", "Korea", 5, 1950, [
"!Early KW U.S. Army rules:"
] )
check_notes( "american", "Korea", 6, 1950, [
"Early KW U.S. Army rules:"
] )
check_notes( "american", "Korea", 9, 1950, [
"!Early KW U.S. Army rules:"
] )
# test the South Korean national Capabilities
check_oba( "kfw-rok", "Korea", 5, 1950, "???", "3R",
comments = [ "Plentiful Ammo included (KMC)" ]
)
check_oba( "kfw-rok", "Korea", 6, 1950, "10B", "3R",
comments = [ "Plentiful Ammo included (KMC)", "ROK: 6B/3R" ]
)
check_oba( "kfw-rok", "Korea", 10, 1950, "10B", "3R", plentiful=True )
check_th_color( "kfw-rok", "Korea", 8, 1950, "Red TH#" )
check_th_color( "kfw-rok", "Korea", 9, 1950, "Red TH# (ROK) ; Black (KMC)" )
check_th_color( "kfw-rok", "Korea", 5, 1951, "Black TH#" )
# test the CPVA national Capabilities
check_notes( "kfw-cpva", "Korea", 9, 1950, [
"!Early KW CPVA rules"
] )
check_notes( "kfw-cpva", "Korea", 10, 1950, [
"Early KW CPVA rules"
] )
check_notes( "kfw-cpva", "Korea", 4, 1951, [
"!Early KW CPVA rules"
] )
check_oba( "kfw-cpva", "Korea", 3, 1951, "-", "-" )
check_oba( "kfw-cpva", "Korea", 4, 1951, "7B", "3R" )
check_oba( "kfw-cpva", "Korea", 11, 1952, "7B", "2R" )