Skip to content

Commit

Permalink
NFC Fix type checking in test_typedoc_analysis (#159)
Browse files Browse the repository at this point in the history
  • Loading branch information
hoodmane authored May 6, 2024
1 parent 36bf56d commit d878a1a
Showing 1 changed file with 70 additions and 19 deletions.
89 changes: 70 additions & 19 deletions tests/test_typedoc_analysis/test_typedoc_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
DescriptionCode,
DescriptionText,
Function,
Interface,
Param,
Pathname,
Return,
Expand Down Expand Up @@ -55,7 +56,7 @@ def commented_object_path(self, comment, **kwargs):
obj = self.commented_object(comment, **kwargs)
if obj is NO_MATCH:
raise RuntimeError(f'No object found with the comment "{comment}".')
return obj.path.segments
return obj.path.segments # type:ignore[attr-defined]

def test_class(self):
assert self.commented_object_path("Foo class") == [
Expand Down Expand Up @@ -201,6 +202,7 @@ def test_class1(self):
nonexistent constructors, members, and top-level attrs are surfaced."""
# Make sure is_abstract is sometimes false:
super = self.analyzer.get_object(["Superclass"])
assert isinstance(super, Class)
assert not super.is_abstract

# There should be a single member representing method():
Expand All @@ -218,6 +220,7 @@ def test_class1(self):
]

subclass2 = self.analyzer.get_object(["EmptySubclass2"])
assert isinstance(subclass2, Class)
assert join_type(subclass2.supers[0]) == "Promise<number>"

# _MembersAndSupers attrs:
Expand Down Expand Up @@ -246,20 +249,23 @@ def test_interface(self):
"""
interface = self.analyzer.get_object(["Interface"])
assert isinstance(interface, Interface)
assert interface.supers == [
[TypeXRefInternal("SuperInterface", ["./", "nodes.", "SuperInterface"])]
]

def test_interface_function_member(self):
"""Make sure function-like properties are understood."""
obj = self.analyzer.get_object(["InterfaceWithMembers"])
assert isinstance(obj, Interface)
prop = obj.members[0]
assert isinstance(prop, Function)
assert prop.name == "callableProperty"

def test_variable(self):
"""Make sure top-level consts and vars are found."""
const = self.analyzer.get_object(["topLevelConst"])
assert isinstance(const, Attribute)
assert const.type == ["3"]

def test_function(self):
Expand Down Expand Up @@ -304,12 +310,14 @@ def test_constructor(self):
"""
cls = self.analyzer.get_object(["ClassWithProperties"])
assert isinstance(cls, Class)
assert isinstance(cls.constructor_, Function)

def test_properties(self):
"""Make sure properties are hooked onto classes and expose their
flags."""
cls = self.analyzer.get_object(["ClassWithProperties"])
assert isinstance(cls, Class)
# The properties are on the class and are Attributes:
assert (
len(
Expand All @@ -323,20 +331,18 @@ def test_properties(self):
)
== 4
)

# The unique things about properties (over and above Variables) are set
# right:
assert self.analyzer.get_object(
["ClassWithProperties.", "someStatic"]
).is_static
assert self.analyzer.get_object(
["ClassWithProperties#", "someOptional"]
).is_optional
assert self.analyzer.get_object(
["ClassWithProperties#", "somePrivate"]
).is_private
normal_property = self.analyzer.get_object(
["ClassWithProperties#", "someNormal"]
)
def get_prop(delim: str, val: str) -> Attribute:
res = self.analyzer.get_object(["ClassWithProperties" + delim, val])
assert isinstance(res, Attribute)
return res

assert get_prop(".", "someStatic").is_static
assert get_prop("#", "someOptional").is_optional
assert get_prop("#", "somePrivate").is_private
normal_property = get_prop("#", "someNormal")
assert (
not normal_property.is_optional
and not normal_property.is_static
Expand Down Expand Up @@ -391,11 +397,13 @@ def test_basic(self):
("sym", "symbol"),
]:
obj = self.analyzer.get_object([obj_name])
assert isinstance(obj, Attribute)
assert join_type(obj.type) == type_name

def test_named_interface(self):
"""Make sure interfaces can be referenced by name."""
obj = self.analyzer.get_object(["interfacer"])
assert isinstance(obj, Function)
assert obj.params[0].type == [
TypeXRefInternal(name="Interface", path=["./", "types.", "Interface"])
]
Expand All @@ -404,7 +412,9 @@ def test_interface_readonly_member(self):
"""Make sure the readonly modifier doesn't keep us from computing the
type of a property."""
obj = self.analyzer.get_object(["Interface"])
assert isinstance(obj, Interface)
read_only_num = obj.members[0]
assert isinstance(read_only_num, Attribute)
assert read_only_num.name == "readOnlyNum"
assert read_only_num.type == [TypeXRefIntrinsic("number")]

Expand All @@ -416,12 +426,14 @@ def test_array(self):
"""
obj = self.analyzer.get_object(["overload"])
assert isinstance(obj, Function)
assert obj.params[0].type == [TypeXRefIntrinsic("string"), "[]"]

def test_literal_types(self):
"""Make sure a thing of a named literal type has that type name
attached."""
obj = self.analyzer.get_object(["certainNumbers"])
assert isinstance(obj, Attribute)
assert obj.type == [
TypeXRefInternal(
name="CertainNumbers", path=["./", "types.", "CertainNumbers"]
Expand All @@ -431,6 +443,7 @@ def test_literal_types(self):
def test_unions(self):
"""Make sure unions get rendered properly."""
obj = self.analyzer.get_object(["union"])
assert isinstance(obj, Attribute)
assert obj.type == [
TypeXRefIntrinsic("number"),
" | ",
Expand All @@ -441,6 +454,7 @@ def test_unions(self):

def test_intersection(self):
obj = self.analyzer.get_object(["intersection"])
assert isinstance(obj, Attribute)
assert obj.type == [
TypeXRefInternal(name="FooHaver", path=["./", "types.", "FooHaver"]),
" & ",
Expand All @@ -450,6 +464,7 @@ def test_intersection(self):
def test_generic_function(self):
"""Make sure type params appear in args and return types."""
obj = self.analyzer.get_object(["aryIdentity"])
assert isinstance(obj, Function)
T = ["T", "[]"]
assert obj.params[0].type == T
assert obj.returns[0].type == T
Expand All @@ -458,6 +473,7 @@ def test_generic_member(self):
"""Make sure members of a class have their type params taken into
account."""
obj = self.analyzer.get_object(["add"])
assert isinstance(obj, Function)
assert obj.name == "add"
assert len(obj.params) == 2
T = ["T"]
Expand All @@ -468,6 +484,7 @@ def test_generic_member(self):
def test_constrained_by_interface(self):
"""Make sure ``extends SomeInterface`` constraints are rendered."""
obj = self.analyzer.get_object(["constrainedIdentity"])
assert isinstance(obj, Function)
T = ["T"]
assert obj.params[0].type == T
assert obj.returns[0].type == T
Expand All @@ -481,7 +498,8 @@ def test_constrained_by_interface(self):

def test_constrained_by_key(self):
"""Make sure ``extends keyof SomeObject`` constraints are rendered."""
obj: Function = self.analyzer.get_object(["getProperty"])
obj = self.analyzer.get_object(["getProperty"])
assert isinstance(obj, Function)
assert obj.params[0].name == "obj"
assert join_type(obj.params[0].type) == "T"
assert join_type(obj.params[1].type) == "K"
Expand All @@ -504,7 +522,7 @@ def test_constrained_by_key(self):
a = AutoFunctionRenderer.__new__(AutoFunctionRenderer)
a._add_span = False
a._set_type_xref_formatter(None)
a._explicit_formal_params = None
a._explicit_formal_params = None # type:ignore[attr-defined]
a._content = []
rst = a.rst([obj.name], obj)
rst = rst.replace("\\", "").replace(" ", " ")
Expand All @@ -516,7 +534,8 @@ def test_constrained_by_key(self):

def test_class_constrained(self):
# TODO: this may belong somewhere else
obj: Class = self.analyzer.get_object(["ParamClass"])
obj = self.analyzer.get_object(["ParamClass"])
assert isinstance(obj, Class)
tp = copy(obj.type_params[0])
tp.extends = join_type(tp.extends)
assert tp == TypeParam(
Expand All @@ -526,7 +545,7 @@ def test_class_constrained(self):
)
a = AutoClassRenderer.__new__(AutoClassRenderer)
a._set_type_xref_formatter(None)
a._explicit_formal_params = None
a._explicit_formal_params = None # type:ignore[attr-defined]
a._add_span = False
a._content = []
a._options = {}
Expand All @@ -538,8 +557,10 @@ def test_constrained_by_constructor(self):
"""Make sure ``new ()`` expressions and, more generally, per-property
constraints are rendered properly."""
obj = self.analyzer.get_object(["create1"])
assert isinstance(obj, Function)
assert join_type(obj.params[0].type) == "{new (x: number) => A}"
obj = self.analyzer.get_object(["create2"])
assert isinstance(obj, Function)
assert join_type(obj.params[0].type) == "{new () => T}"

def test_utility_types(self):
Expand All @@ -549,8 +570,12 @@ def test_utility_types(self):
TypeXRefExternal
"""
obj = self.analyzer.get_object(["partial"])
assert isinstance(obj, Attribute)
t = deepcopy(obj.type)
t[0].sourcefilename = "xxx"
assert t
s = t[0]
assert isinstance(s, TypeXRefExternal)
s.sourcefilename = "xxx"
assert t == [
TypeXRefExternal("Partial", "typescript", "xxx", "Partial"),
"<",
Expand All @@ -564,12 +589,14 @@ def test_internal_symbol_reference(self):
TypeXRefInternal
"""
obj = self.analyzer.get_object(["internalSymbolReference"])
assert isinstance(obj, Attribute)
assert obj.type == [
TypeXRefInternal(name="Blah", path=["./", "exports"], type="internal")
]

def test_constrained_by_property(self):
obj = self.analyzer.get_object(["objProps"])
assert isinstance(obj, Function)
assert obj.params[0].type == [
"{ ",
"label",
Expand All @@ -585,6 +612,7 @@ def test_constrained_by_property(self):
def test_optional_property(self):
"""Make sure optional properties render properly."""
obj = self.analyzer.get_object(["option"])
assert isinstance(obj, Attribute)
assert join_type(obj.type) == "{ a: number; b?: string; }"

def test_code_in_description(self):
Expand All @@ -603,6 +631,7 @@ def test_code_in_description(self):

def test_destructured(self):
obj = self.analyzer.get_object(["destructureTest"])
assert isinstance(obj, Function)
# Parameters should be sorted by source position in the type annotation not by name.
assert obj.params[0].name == "options.b"
assert join_type(obj.params[0].type) == "{ c: string; }"
Expand All @@ -612,6 +641,7 @@ def test_destructured(self):
assert obj.params[1].description == [DescriptionText(text="The 'a' string.")]

obj = self.analyzer.get_object(["destructureTest2"])
assert isinstance(obj, Function)
assert obj.params[0].name == "options.b"
assert join_type(obj.params[0].type) == "{ c: string; }"
assert obj.params[0].description == [DescriptionText(text="The 'b' object.")]
Expand All @@ -621,73 +651,94 @@ def test_destructured(self):
assert obj.params[1].description == [DescriptionText(text="The 'a' string.")]

obj = self.analyzer.get_object(["destructureTest3"])
assert isinstance(obj, Function)
assert obj.params[0].name == "options"
assert join_type(obj.params[0].type) == "{ a: string; b: { c: string; }; }"

obj = self.analyzer.get_object(["destructureTest4"])
assert isinstance(obj, Function)
assert obj.params[0].name == "destructureThisPlease.a"
assert join_type(obj.params[0].type) == "string"
assert obj.params[0].description == [DescriptionText(text="The 'a' string.")]

def test_funcarg(self):
obj = self.analyzer.get_object(["funcArg"])
assert isinstance(obj, Function)
assert obj.params[0].name == "a"
assert join_type(obj.params[0].type) == "(b: number, c: number) => number"

def test_namedtuplearg(self):
obj = self.analyzer.get_object(["namedTupleArg"])
assert isinstance(obj, Function)
assert obj.params[0].name == "namedTuple"
assert join_type(obj.params[0].type) == "[key: string, value: any]"

def test_query(self):
obj = self.analyzer.get_object(["queryType"])
assert isinstance(obj, Attribute)
assert join_type(obj.type) == "typeof A"

def test_type_operator(self):
obj = self.analyzer.get_object(["typeOperatorType"])
assert isinstance(obj, Attribute)
assert join_type(obj.type) == "keyof A"

def test_private_type_alias1(self):
obj = self.analyzer.get_object(["typeIsPrivateTypeAlias1"])
assert isinstance(obj, Attribute)
assert join_type(obj.type) == "{ a: number; b: string; }"

def test_private_type_alias2(self):
obj = self.analyzer.get_object(["typeIsPrivateTypeAlias2"])
assert isinstance(obj, Attribute)
assert join_type(obj.type) == "{ a: number; b: string; }"

def test_hidden_type_top_level(self):
obj = self.analyzer.get_object(["hiddenType"])
assert obj.modifier_tags == ["@hidetype"]
assert isinstance(obj, Attribute)
assert obj.type == []

def test_hidden_type_member(self):
obj = self.analyzer.get_object(["HasHiddenTypeMember"])
assert obj.members[0].type == []
assert isinstance(obj, Class)
assert obj.members
member = obj.members[0]
assert isinstance(member, Attribute)
assert member.type == []

def test_rest_type(self):
obj = self.analyzer.get_object(["restType"])
assert isinstance(obj, Attribute)
assert join_type(obj.type) == "[...number[]]"

def test_indexed_access_type(self):
obj = self.analyzer.get_object(["indexedAccessType"])
assert isinstance(obj, Attribute)
assert join_type(obj.type) == 'FunctionInterface["length"]'

def test_conditional_type(self):
obj = self.analyzer.get_object(["ConditionalType"])
assert isinstance(obj, TypeAlias)
assert join_type(obj.type) == "T extends A ? 1 : 2"

def test_inferred_type(self):
obj = self.analyzer.get_object(["InferredType"])
assert isinstance(obj, TypeAlias)
assert join_type(obj.type) == "T extends Promise<infer S> ? S : T"

def test_mapped_type(self):
obj = self.analyzer.get_object(["MappedType1"])
assert isinstance(obj, TypeAlias)
assert join_type(obj.type) == "{ [property in keys]: number }"
obj = self.analyzer.get_object(["MappedType2"])
assert isinstance(obj, TypeAlias)
assert join_type(obj.type) == "{ -readonly [property in keys]?: number }"
obj = self.analyzer.get_object(["MappedType3"])
assert isinstance(obj, TypeAlias)
assert join_type(obj.type) == "{ readonly [property in keys]-?: number }"

def test_template_literal(self):
obj = self.analyzer.get_object(["TemplateLiteral"])
assert isinstance(obj, TypeAlias)
assert join_type(obj.type) == "`${number}: ${string}`"

0 comments on commit d878a1a

Please sign in to comment.