Skip to content

Commit

Permalink
Adding a unit test for implicitly generic classes
Browse files Browse the repository at this point in the history
  • Loading branch information
majakusber committed Nov 27, 2017
1 parent ba05f18 commit 0163362
Show file tree
Hide file tree
Showing 11 changed files with 305 additions and 3 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class GenericClassWithInnerClasses<T>
{
class Inner {
T t1;
Generic<T> t2;

class InnerInner {
T tt1;
Generic<Generic<T>> tt2;
}
}

class GenericInner<U> {
T gt1;
GenericTwoParam<T,U> gt2;

class GenericInnerInner<V>{

}
}

static class StaticInner<U>{
U st;
}

Inner f1;
Inner.InnerInner f2;
GenericInner<Integer> f3;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/*******************************************************************\
Module: Unit tests for parsing generic classes
Author: DiffBlue Limited. All rights reserved.
\*******************************************************************/

#include <testing-utils/catch.hpp>
#include <testing-utils/load_java_class.h>
#include <testing-utils/require_type.h>

SCENARIO(
"parse_generic_class_with_inner_classes",
"[core][java_bytecode][java_bytecode_parse_generics]")
{
const symbol_tablet &new_symbol_table = load_java_class(
"GenericClassWithInnerClasses",
"./java_bytecode/java_bytecode_parse_generics");

std::string outer_class_prefix = "java::GenericClassWithInnerClasses";

WHEN("Generic outer class has fields which are objects of the inner classes")
{
REQUIRE(new_symbol_table.has_symbol(outer_class_prefix));
const symbolt &class_symbol =
new_symbol_table.lookup_ref(outer_class_prefix);
const java_generic_class_typet &generic_class =
require_type::require_java_generic_class(
class_symbol.type, {outer_class_prefix + "::T"});
THEN("There is a field f1 of generic type with correct arguments")
{
const auto &field = require_type::require_component(generic_class, "f1");
require_type::require_pointer(
field.type(), symbol_typet(outer_class_prefix + "$Inner"));
require_type::require_java_generic_type(
field.type(),
{{require_type::type_argument_kindt::Var, outer_class_prefix + "::T"}});
}
THEN("There is a field f2 of generic type with correct arguments")
{
const auto &field = require_type::require_component(generic_class, "f2");
require_type::require_pointer(
field.type(), symbol_typet(outer_class_prefix + "$Inner$InnerInner"));
require_type::require_java_generic_type(
field.type(),
{{require_type::type_argument_kindt::Var, outer_class_prefix + "::T"}});
}
THEN("There is a field f3 of generic type with correct arguments")
{
const auto &field = require_type::require_component(generic_class, "f3");
require_type::require_pointer(
field.type(), symbol_typet(outer_class_prefix + "$GenericInner"));
require_type::require_java_generic_type(
field.type(),
{{require_type::type_argument_kindt::Var, outer_class_prefix + "::T"},
{require_type::type_argument_kindt::Inst, "java::java.lang.Integer"}});
}
}

WHEN("Inner class of a generic outer class is parsed")
{
std::string inner_class_prefix = outer_class_prefix + "$Inner";
REQUIRE(new_symbol_table.has_symbol(inner_class_prefix));
const symbolt &class_symbol =
new_symbol_table.lookup_ref(inner_class_prefix);

THEN("It has correct implicit generic types")
{
const java_implicitly_generic_class_typet &java_class =
require_type::require_java_implicitly_generic_class(
class_symbol.type, {outer_class_prefix + "::T"});

THEN(
"There is a field t1 which is the generic parameter of the outer "
"class")
{
const auto &field = require_type::require_component(java_class, "t1");
require_type::require_java_generic_parameter(
field.type(), outer_class_prefix + "::T");
}
THEN(
"There is a field t2 of generic type with the generic "
"parameter of the outer class")
{
const auto &field = require_type::require_component(java_class, "t2");
require_type::require_pointer(
field.type(), symbol_typet("java::Generic"));
require_type::require_java_generic_type(
field.type(),
{{require_type::type_argument_kindt::Var,
outer_class_prefix + "::T"}});
}
}
}

WHEN("Inner class of an inner class of a generic outer class is parsed")
{
std::string inner_inner_class_prefix =
outer_class_prefix + "$Inner$InnerInner";
REQUIRE(new_symbol_table.has_symbol(inner_inner_class_prefix));
const symbolt &class_symbol =
new_symbol_table.lookup_ref(inner_inner_class_prefix);

THEN("It has correct implicit generic types")
{
const java_implicitly_generic_class_typet &java_class =
require_type::require_java_implicitly_generic_class(
class_symbol.type, {outer_class_prefix + "::T"});

THEN(
"There is a field tt1 which is the generic parameter of the outer "
"class")
{
const auto &field = require_type::require_component(java_class, "tt1");
require_type::require_java_generic_parameter(
field.type(), outer_class_prefix + "::T");
}
THEN(
"There is a field tt2 of nested generic type with the generic "
"parameter of the outer class")
{
const auto &field = require_type::require_component(java_class, "tt2");
require_type::require_pointer(
field.type(), symbol_typet("java::Generic"));
const java_generic_typet &generic_field =
require_type::require_java_generic_type(
field.type(),
{{require_type::type_argument_kindt::Inst, "java::Generic"}});

const typet &type_argument =
generic_field.generic_type_arguments().at(0);
const java_generic_typet generic_type_argument =
require_type::require_java_generic_type(
type_argument,
{{require_type::type_argument_kindt::Var,
outer_class_prefix + "::T"}});
}
}
}

WHEN("Generic inner class of a generic outer class is parsed")
{
std::string generic_inner_class_prefix =
outer_class_prefix + "$GenericInner";
REQUIRE(new_symbol_table.has_symbol(generic_inner_class_prefix));
const symbolt &class_symbol =
new_symbol_table.lookup_ref(generic_inner_class_prefix);

THEN("It has correct generic types and implicit generic types")
{
require_type::require_java_implicitly_generic_class(
class_symbol.type, {outer_class_prefix + "::T"});
const java_generic_class_typet &generic_class =
require_type::require_java_generic_class(
class_symbol.type, {generic_inner_class_prefix + "::U"});

THEN(
"There is a field gt1 which is the generic parameter of the outer "
"class")
{
const auto &field =
require_type::require_component(generic_class, "gt1");
require_type::require_java_generic_parameter(
field.type(), outer_class_prefix + "::T");
}
THEN(
"There is a field gt2 of generic type with the generic "
"parameter of the outer class")
{
const auto &field =
require_type::require_component(generic_class, "gt2");
require_type::require_pointer(
field.type(), symbol_typet("java::GenericTwoParam"));
require_type::require_java_generic_type(
field.type(),
{{require_type::type_argument_kindt::Var,
outer_class_prefix + "::T"},
{require_type::type_argument_kindt::Var,
generic_inner_class_prefix + "::U"}});
}
}
}

WHEN(
"A generic inner class of a generic inner class of a generic outer class "
"is parsed")
{
std::string generic_inner_inner_class_prefix =
outer_class_prefix + "$GenericInner$GenericInnerInner";
REQUIRE(new_symbol_table.has_symbol(generic_inner_inner_class_prefix));
const symbolt &class_symbol =
new_symbol_table.lookup_ref(generic_inner_inner_class_prefix);

THEN("It has correct generic types and implicit generic types")
{
require_type::require_java_implicitly_generic_class(
class_symbol.type,
{outer_class_prefix + "::T", outer_class_prefix + "$GenericInner::U"});
require_type::require_java_generic_class(
class_symbol.type, {generic_inner_inner_class_prefix + "::V"});
}
}

WHEN("A static generic inner class of a generic class is parsed")
{
std::string static_inner_class_prefix = outer_class_prefix + "$StaticInner";
REQUIRE(new_symbol_table.has_symbol(static_inner_class_prefix));
const symbolt &class_symbol =
new_symbol_table.lookup_ref(static_inner_class_prefix);

THEN("It has correct generic types and no implicit generic types")
{
REQUIRE(!is_java_implicitly_generic_class_type(class_symbol.type));
require_type::require_java_generic_class(
class_symbol.type, {static_inner_class_prefix + "::U"});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ SCENARIO(

const symbolt &inner_symbol = new_symbol_table.lookup_ref(inner_prefix);
const class_typet &inner_class_type =
require_type::require_java_non_generic_class(inner_symbol.type);
require_type::require_java_implicitly_generic_class(inner_symbol.type);
}

THEN(
Expand Down Expand Up @@ -63,8 +63,7 @@ SCENARIO(

const symbolt &inner_enum_symbol =
new_symbol_table.lookup_ref(inner_enum_prefix);
const class_typet &inner_enum_class_type =
require_type::require_java_non_generic_class(inner_enum_symbol.type);
require_type::require_java_non_generic_class(inner_enum_symbol.type);
}

THEN(
Expand Down
48 changes: 48 additions & 0 deletions unit/testing-utils/require_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,53 @@ java_generic_class_typet require_type::require_java_generic_class(
return java_generic_class_type;
}

/// Verify that a class is a complete, valid java implicitly generic class.
/// \param class_type: the class
/// \return: A reference to the java generic class type.
java_implicitly_generic_class_typet
require_type::require_java_implicitly_generic_class(const typet &class_type)
{
const class_typet &class_class_type = require_complete_class(class_type);
java_class_typet java_class_type = to_java_class_type(class_class_type);

REQUIRE(is_java_implicitly_generic_class_type(java_class_type));
java_implicitly_generic_class_typet java_implicitly_generic_class_type =
to_java_implicitly_generic_class_type(java_class_type);

return java_implicitly_generic_class_type;
}

/// Verify that a class is a complete, valid java generic class with the
/// specified list of variables.
/// \param class_type: the class
/// \param type_variables: vector of type variables
/// \return: A reference to the java generic class type.
java_implicitly_generic_class_typet
require_type::require_java_implicitly_generic_class(
const typet &class_type,
const std::initializer_list<irep_idt> &implicit_type_variables)
{
const java_implicitly_generic_class_typet java_implicitly_generic_class_type =
require_type::require_java_implicitly_generic_class(class_type);

const java_implicitly_generic_class_typet::implicit_generic_typest
&implicit_generic_type_vars =
java_implicitly_generic_class_type.implicit_generic_types();
REQUIRE(implicit_generic_type_vars.size() == implicit_type_variables.size());
REQUIRE(
std::equal(
implicit_type_variables.begin(),
implicit_type_variables.end(),
implicit_generic_type_vars.begin(),
[](const irep_idt &type_var_name, const java_generic_parametert &param)
{
REQUIRE(is_java_generic_parameter(param));
return param.type_variable().get_identifier() == type_var_name;
}));

return java_implicitly_generic_class_type;
}

/// Verify that a class is a complete, valid nongeneric java class
/// \param class_type: the class
/// \return: A reference to the java generic class type.
Expand All @@ -280,6 +327,7 @@ require_type::require_java_non_generic_class(const typet &class_type)
java_class_typet java_class_type = to_java_class_type(class_class_type);

REQUIRE(!is_java_generic_class_type(java_class_type));
REQUIRE(!is_java_implicitly_generic_class_type(java_class_type));

return java_class_type;
}
Expand Down
7 changes: 7 additions & 0 deletions unit/testing-utils/require_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ java_generic_class_typet require_java_generic_class(
const typet &class_type,
const std::initializer_list<irep_idt> &type_parameters);

java_implicitly_generic_class_typet
require_java_implicitly_generic_class(const typet &class_type);

java_implicitly_generic_class_typet require_java_implicitly_generic_class(
const typet &class_type,
const std::initializer_list<irep_idt> &implicit_type_variables);

java_class_typet require_java_non_generic_class(const typet &class_type);
}

Expand Down

0 comments on commit 0163362

Please sign in to comment.