Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Adam Osuchowski
Kea
Commits
1bbe1315
Commit
1bbe1315
authored
Nov 30, 2012
by
Marcin Siodelski
Browse files
[2491] Added first set of functions to set data field values.
parent
8a21830a
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/lib/dhcp/option_custom.cc
View file @
1bbe1315
...
...
@@ -20,12 +20,19 @@
namespace
isc
{
namespace
dhcp
{
OptionCustom
::
OptionCustom
(
const
OptionDefinition
&
def
,
Universe
u
)
:
Option
(
u
,
def
.
getCode
(),
OptionBuffer
()),
definition_
(
def
)
{
createBuffers
();
}
OptionCustom
::
OptionCustom
(
const
OptionDefinition
&
def
,
Universe
u
,
const
OptionBuffer
&
data
)
:
Option
(
u
,
def
.
getCode
(),
data
.
begin
(),
data
.
end
()),
definition_
(
def
)
{
createBuffers
();
createBuffers
(
data_
);
}
OptionCustom
::
OptionCustom
(
const
OptionDefinition
&
def
,
...
...
@@ -34,7 +41,7 @@ OptionCustom::OptionCustom(const OptionDefinition& def,
OptionBufferConstIter
last
)
:
Option
(
u
,
def
.
getCode
(),
first
,
last
),
definition_
(
def
)
{
createBuffers
();
createBuffers
(
data_
);
}
void
...
...
@@ -45,14 +52,83 @@ OptionCustom::checkIndex(const uint32_t index) const {
}
}
template
<
typename
T
>
void
OptionCustom
::
checkDataType
(
const
uint32_t
index
)
const
{
// Check that the requested return type is a supported integer.
if
(
!
OptionDataTypeTraits
<
T
>::
integer_type
)
{
isc_throw
(
isc
::
dhcp
::
InvalidDataType
,
"specified data type"
" is not a supported integer type."
);
}
// Get the option definition type.
OptionDataType
data_type
=
definition_
.
getType
();
if
(
data_type
==
OPT_RECORD_TYPE
)
{
const
OptionDefinition
::
RecordFieldsCollection
&
record_fields
=
definition_
.
getRecordFields
();
// When we initialized buffers we have already checked that
// the number of these buffers is equal to number of option
// fields in the record so the condition below should be met.
assert
(
index
<
record_fields
.
size
());
// Get the data type to be returned.
data_type
=
record_fields
[
index
];
}
if
(
OptionDataTypeTraits
<
T
>::
type
!=
data_type
)
{
isc_throw
(
isc
::
dhcp
::
InvalidDataType
,
"specified data type "
<<
data_type
<<
" does not"
"match data type in an option definition for field"
" index "
<<
index
);
}
}
void
OptionCustom
::
createBuffers
()
{
definition_
.
validate
();
std
::
vector
<
OptionBuffer
>
buffers
;
OptionDataType
data_type
=
definition_
.
getType
();
if
(
data_type
==
OPT_RECORD_TYPE
)
{
const
OptionDefinition
::
RecordFieldsCollection
fields
=
definition_
.
getRecordFields
();
for
(
OptionDefinition
::
RecordFieldsConstIter
field
=
fields
.
begin
();
field
!=
fields
.
end
();
++
field
)
{
OptionBuffer
buf
;
size_t
data_size
=
OptionDataTypeUtil
::
getDataTypeLen
(
*
field
);
if
(
data_size
==
0
&&
*
field
==
OPT_FQDN_TYPE
)
{
OptionDataTypeUtil
::
writeFqdn
(
"."
,
buf
);
}
else
{
buf
.
resize
(
data_size
);
}
buffers
.
push_back
(
buf
);
}
}
else
if
(
!
definition_
.
getArrayType
()
&&
data_type
!=
OPT_EMPTY_TYPE
)
{
OptionBuffer
buf
;
size_t
data_size
=
OptionDataTypeUtil
::
getDataTypeLen
(
data_type
);
if
(
data_size
==
0
&&
data_type
==
OPT_FQDN_TYPE
)
{
OptionDataTypeUtil
::
writeFqdn
(
"."
,
buf
);
}
buf
.
resize
(
data_size
);
buffers
.
push_back
(
buf
);
}
std
::
swap
(
buffers
,
buffers_
);
}
void
OptionCustom
::
createBuffers
(
const
OptionBuffer
&
data_buf
)
{
// Check that the option definition is correct as we are going
// to use it to split the data_ buffer into set of sub buffers.
definition_
.
validate
();
std
::
vector
<
OptionBuffer
>
buffers
;
OptionBuffer
::
iterator
data
=
data_
.
begin
();
OptionBuffer
::
const_
iterator
data
=
data_
buf
.
begin
();
OptionDataType
data_type
=
definition_
.
getType
();
if
(
data_type
==
OPT_RECORD_TYPE
)
{
...
...
@@ -78,7 +154,7 @@ OptionCustom::createBuffers() {
// to obtain the length of the data is to read the FQDN. The
// utility function will return the size of the buffer on success.
if
(
*
field
==
OPT_FQDN_TYPE
)
{
OptionDataTypeUtil
::
readFqdn
(
OptionBuffer
(
data
,
data_
.
end
()),
OptionDataTypeUtil
::
readFqdn
(
OptionBuffer
(
data
,
data_
buf
.
end
()),
data_size
);
}
else
{
// In other case we are dealing with string or binary value
...
...
@@ -87,7 +163,7 @@ OptionCustom::createBuffers() {
// size data can be laid at the end of the option only and
// that the validate() function in OptionDefinition object
// should have checked wheter it is a case for this option.
data_size
=
std
::
distance
(
data
,
data_
.
end
());
data_size
=
std
::
distance
(
data
,
data_
buf
.
end
());
}
if
(
data_size
==
0
)
{
// If we reached the end of buffer we assume that this option is
...
...
@@ -100,7 +176,7 @@ OptionCustom::createBuffers() {
}
else
{
// Our data field requires that there is a certain chunk of
// data left in the buffer. If not, option is truncated.
if
(
std
::
distance
(
data
,
data_
.
end
())
<
data_size
)
{
if
(
std
::
distance
(
data
,
data_
buf
.
end
())
<
data_size
)
{
isc_throw
(
OutOfRange
,
"option buffer truncated"
);
}
}
...
...
@@ -121,19 +197,19 @@ OptionCustom::createBuffers() {
// Note that data_size returned by getDataTypeLen may be zero
// if variable length data is being held by the option but
// this will not cause this check to throw exception.
if
(
std
::
distance
(
data
,
data_
.
end
())
<
data_size
)
{
if
(
std
::
distance
(
data
,
data_
buf
.
end
())
<
data_size
)
{
isc_throw
(
OutOfRange
,
"option buffer truncated"
);
}
// For an array of values we are taking different path because
// we have to handle multiple buffers.
if
(
definition_
.
getArrayType
())
{
while
(
data
!=
data_
.
end
())
{
while
(
data
!=
data_
buf
.
end
())
{
// FQDN is a special case because it is of a variable length.
// The actual length for a particular FQDN is encoded within
// a buffer so we have to actually read the FQDN from a buffer
// to get it.
if
(
data_type
==
OPT_FQDN_TYPE
)
{
OptionDataTypeUtil
::
readFqdn
(
OptionBuffer
(
data
,
data_
.
end
()),
OptionDataTypeUtil
::
readFqdn
(
OptionBuffer
(
data
,
data_
buf
.
end
()),
data_size
);
}
// We don't perform other checks for data types that can't be
...
...
@@ -147,7 +223,7 @@ OptionCustom::createBuffers() {
// data_size. Note that it is ok to truncate the data if and only
// if the data buffer is long enough to keep at least one value.
// This has been checked above already.
if
(
std
::
distance
(
data
,
data_
.
end
())
<
data_size
)
{
if
(
std
::
distance
(
data
,
data_
buf
.
end
())
<
data_size
)
{
break
;
}
buffers
.
push_back
(
OptionBuffer
(
data
,
data
+
data_size
));
...
...
@@ -160,10 +236,10 @@ OptionCustom::createBuffers() {
if
(
data_size
==
0
)
{
// For FQDN we get the size by actually reading the FQDN.
if
(
data_type
==
OPT_FQDN_TYPE
)
{
OptionDataTypeUtil
::
readFqdn
(
OptionBuffer
(
data
,
data_
.
end
()),
OptionDataTypeUtil
::
readFqdn
(
OptionBuffer
(
data
,
data_
buf
.
end
()),
data_size
);
}
else
{
data_size
=
std
::
distance
(
data
,
data_
.
end
());
data_size
=
std
::
distance
(
data
,
data_
buf
.
end
());
}
}
if
(
data_size
>
0
)
{
...
...
@@ -286,6 +362,28 @@ OptionCustom::readAddress(const uint32_t index) const {
}
}
void
OptionCustom
::
writeAddress
(
const
asiolink
::
IOAddress
&
address
,
const
uint32_t
index
)
{
using
namespace
isc
::
asiolink
;
checkIndex
(
index
);
if
((
address
.
getFamily
()
==
AF_INET
&&
buffers_
[
index
].
size
()
!=
V4ADDRESS_LEN
)
||
(
address
.
getFamily
()
==
AF_INET6
&&
buffers_
[
index
].
size
()
!=
V6ADDRESS_LEN
))
{
isc_throw
(
BadDataTypeCast
,
"invalid address specified "
<<
address
.
toText
()
<<
". Expected a valid IPv"
<<
(
buffers_
[
index
].
size
()
==
V4ADDRESS_LEN
?
"4"
:
"6"
)
<<
" address."
);
}
OptionBuffer
buf
;
OptionDataTypeUtil
::
writeAddress
(
address
,
buf
);
std
::
swap
(
buf
,
buffers_
[
index
]);
}
const
OptionBuffer
&
OptionCustom
::
readBinary
(
const
uint32_t
index
)
const
{
checkIndex
(
index
);
...
...
@@ -298,6 +396,14 @@ OptionCustom::readBoolean(const uint32_t index) const {
return
(
OptionDataTypeUtil
::
readBool
(
buffers_
[
index
]));
}
void
OptionCustom
::
writeBoolean
(
const
bool
value
,
const
uint32_t
index
)
{
checkIndex
(
index
);
buffers_
[
index
].
clear
();
OptionDataTypeUtil
::
writeBool
(
value
,
buffers_
[
index
]);
}
std
::
string
OptionCustom
::
readFqdn
(
const
uint32_t
index
)
const
{
checkIndex
(
index
);
...
...
@@ -315,12 +421,23 @@ OptionCustom::readString(const uint32_t index) const {
return
(
OptionDataTypeUtil
::
readString
(
buffers_
[
index
]));
}
void
OptionCustom
::
writeString
(
const
std
::
string
&
text
,
const
uint32_t
index
)
{
checkIndex
(
index
);
if
(
!
text
.
empty
())
{
buffers_
[
index
].
clear
();
OptionDataTypeUtil
::
writeString
(
text
,
buffers_
[
index
]);
}
}
void
OptionCustom
::
unpack
(
OptionBufferConstIter
begin
,
OptionBufferConstIter
end
)
{
data_
=
OptionBuffer
(
begin
,
end
);
// Chop the buffer stored in data_ into set of sub buffers.
createBuffers
();
createBuffers
(
data_
);
}
uint16_t
...
...
@@ -352,7 +469,7 @@ void OptionCustom::setData(const OptionBufferConstIter first,
// Chop the data_ buffer into set of buffers that represent
// option fields data.
createBuffers
();
createBuffers
(
data_
);
}
std
::
string
OptionCustom
::
toText
(
int
indent
)
{
...
...
src/lib/dhcp/option_custom.h
View file @
1bbe1315
...
...
@@ -38,6 +38,17 @@ namespace dhcp {
class
OptionCustom
:
public
Option
{
public:
/// @brief Constructor, used for options to be sent.
///
/// This constructor creates an instance of an option with default
/// data set for all data fields. The option buffers are allocated
/// according to data size being stored in particular data fields.
/// For variable size data empty buffers are created.
///
/// @param def option definition.
/// @param u specifies universe (V4 or V6)
OptionCustom
(
const
OptionDefinition
&
def
,
Universe
u
);
/// @brief Constructor, used for options to be sent.
///
/// This constructor creates an instance of an option from the whole
...
...
@@ -87,7 +98,17 @@ public:
///
/// @return IP address read from a buffer.
/// @throw isc::OutOfRange if index is out of range.
asiolink
::
IOAddress
readAddress
(
const
uint32_t
index
)
const
;
asiolink
::
IOAddress
readAddress
(
const
uint32_t
index
=
0
)
const
;
/// @brief Write an IP address into a buffer.
///
/// @param address IP address being written.
/// @param index buffer index.
///
/// @throw isc::OutOfRange if index is out of range.
/// @throw isc::dhcp::BadDataTypeCast if IP address is invalid.
void
writeAddress
(
const
asiolink
::
IOAddress
&
address
,
const
uint32_t
index
=
0
);
/// @brief Read a buffer as binary data.
///
...
...
@@ -95,7 +116,7 @@ public:
///
/// @throw isc::OutOfRange if index is out of range.
/// @return read buffer holding binary data.
const
OptionBuffer
&
readBinary
(
const
uint32_t
index
)
const
;
const
OptionBuffer
&
readBinary
(
const
uint32_t
index
=
0
)
const
;
/// @brief Read a buffer as boolean value.
///
...
...
@@ -103,7 +124,15 @@ public:
///
/// @throw isc::OutOfRange if index is out of range.
/// @return read boolean value.
bool
readBoolean
(
const
uint32_t
index
)
const
;
bool
readBoolean
(
const
uint32_t
index
=
0
)
const
;
/// @brief Write a boolean value into a buffer.
///
/// @param value boolean value to be written.
/// @param index buffer index.
///
/// @throw isc::OutOfRange if index is out of range.
void
writeBoolean
(
const
bool
value
,
const
uint32_t
index
=
0
);
/// @brief Read a buffer as FQDN.
///
...
...
@@ -114,7 +143,7 @@ public:
/// @throw isc::dhcp::BadDataTypeCast if a buffer being read
/// does not hold a valid FQDN.
/// @return string representation if FQDN.
std
::
string
readFqdn
(
const
uint32_t
index
)
const
;
std
::
string
readFqdn
(
const
uint32_t
index
=
0
)
const
;
/// @brief Read a buffer as integer value.
///
...
...
@@ -122,38 +151,15 @@ public:
/// @tparam integer type of a value being returned.
///
/// @throw isc::OutOfRange if index is out of range.
/// @throw isc::dhcp::InvalidDataType if T is invalid.
/// @return read integer value.
template
<
typename
T
>
T
readInteger
(
const
uint32_t
index
)
const
{
T
readInteger
(
const
uint32_t
index
=
0
)
const
{
// Check thet tha index is not out of range.
checkIndex
(
index
);
// Check that the requested return type is a supported integer.
if
(
!
OptionDataTypeTraits
<
T
>::
integer_type
)
{
isc_throw
(
isc
::
dhcp
::
InvalidDataType
,
"specified data type to be returned"
" by readInteger is not supported integer type"
);
}
// Get the option definition type.
OptionDataType
data_type
=
definition_
.
getType
();
if
(
data_type
==
OPT_RECORD_TYPE
)
{
const
OptionDefinition
::
RecordFieldsCollection
&
record_fields
=
definition_
.
getRecordFields
();
// When we initialized buffers we have already checked that
// the number of these buffers is equal to number of option
// fields in the record so the condition below should be met.
assert
(
index
<
record_fields
.
size
());
// Get the data type to be returned.
data_type
=
record_fields
[
index
];
}
// Requested data type must match the data type in a record.
if
(
OptionDataTypeTraits
<
T
>::
type
!=
data_type
)
{
isc_throw
(
isc
::
dhcp
::
InvalidDataType
,
"unable to read option field with index "
<<
index
<<
" as integer value. The field's data type"
<<
data_type
<<
" does not match the integer type"
<<
"returned by the readInteger function."
);
}
// Check that T points to a valid integer type and this type
// is consistent with an option definition.
checkDataType
<
T
>
(
index
);
// When we created the buffer we have checked that it has a
// valid size so this condition here should be always fulfiled.
assert
(
buffers_
[
index
].
size
()
==
OptionDataTypeTraits
<
T
>::
len
);
...
...
@@ -161,13 +167,43 @@ public:
return
(
OptionDataTypeUtil
::
readInt
<
T
>
(
buffers_
[
index
]));
}
/// @brief Write an integer value into a buffer.
///
/// @param value integer value to be written.
/// @param index buffer index.
/// @tparam T integer type of a value being written.
///
/// @throw isc::OutOfRange if index is out of range.
/// @throw isc::dhcp::InvalidDataType if T is invalid.
template
<
typename
T
>
void
writeInteger
(
const
T
value
,
const
uint32_t
index
=
0
)
{
// Check that the index is not out of range.
checkIndex
(
index
);
// Check that T points to a valid integer type and this type
// is consistent with an option definition.
checkDataType
<
T
>
(
index
);
// Get some temporary buffer.
OptionBuffer
buf
;
// Try to write to the buffer.
OptionDataTypeUtil
::
writeInt
<
T
>
(
value
,
buf
);
// If successful, replace the old buffer with new one.
std
::
swap
(
buffers_
[
index
],
buf
);
}
/// @brief Read a buffer as string value.
///
/// @param index buffer index.
///
/// @return string value read from buffer.
/// @throw isc::OutOfRange if index is out of range.
std
::
string
readString
(
const
uint32_t
index
)
const
;
std
::
string
readString
(
const
uint32_t
index
=
0
)
const
;
/// @brief Write a string value into a buffer.
///
/// @param text the string value to be written.
/// @param buffer index.
void
writeString
(
const
std
::
string
&
text
,
const
uint32_t
index
=
0
);
/// @brief Parses received buffer.
///
...
...
@@ -219,9 +255,27 @@ private:
/// @throw isc::OutOfRange if index is out of range.
void
checkIndex
(
const
uint32_t
index
)
const
;
/// @brief Create collection of buffers representing data field values.
/// @brief Verify that the integer type is consistent with option
/// field type.
///
/// This convenience function checks that the data type specified as T
/// is consistent with a type of a data field identified by index.
///
/// @param index data field index.
/// @tparam data type to be validated.
///
/// @throw isc::dhcp::InvalidDataType if the type is invalid.
template
<
typename
T
>
void
checkDataType
(
const
uint32_t
index
)
const
;
/// @brief Create a collection of non initialized buffers.
void
createBuffers
();
/// @brief Create collection of buffers representing data field values.
///
/// @param data_buf a buffer to be parsed.
void
createBuffers
(
const
OptionBuffer
&
data_buf
);
/// @brief Return a text representation of a data field.
///
/// @param data_type data type of a field.
...
...
src/lib/dhcp/tests/option_custom_unittest.cc
View file @
1bbe1315
...
...
@@ -106,6 +106,17 @@ TEST_F(OptionCustomTest, constructor) {
EXPECT_EQ
(
Option
::
V4
,
option
->
getUniverse
());
EXPECT_EQ
(
232
,
option
->
getType
());
// Try to create an option using 'empty data' constructor
OptionDefinition
opt_def3
(
"OPTION_FOO"
,
1000
,
"uint32"
);
ASSERT_NO_THROW
(
option
.
reset
(
new
OptionCustom
(
opt_def3
,
Option
::
V6
));
);
ASSERT_TRUE
(
option
);
EXPECT_EQ
(
Option
::
V6
,
option
->
getUniverse
());
EXPECT_EQ
(
1000
,
option
->
getType
());
}
// The purpose of this test is to verify that 'empty' option definition can
...
...
@@ -777,6 +788,134 @@ TEST_F(OptionCustomTest, recordDataTruncated) {
);
}
// The purpose of this test is to verify that an option comprising
// single boolean data field can be created and that its default
// value can be overriden by a new value.
TEST_F
(
OptionCustomTest
,
setBooleanData
)
{
OptionDefinition
opt_def
(
"OPTION_FOO"
,
1000
,
"boolean"
);
// Create an option and let the data field be initialized
// to default value (do not provide any data buffer).
boost
::
scoped_ptr
<
OptionCustom
>
option
;
ASSERT_NO_THROW
(
option
.
reset
(
new
OptionCustom
(
opt_def
,
Option
::
V6
));
);
ASSERT_TRUE
(
option
);
// Check that the default boolean value is false.
bool
value
=
false
;
ASSERT_NO_THROW
(
value
=
option
->
readBoolean
());
EXPECT_FALSE
(
value
);
// Check that we can override the default value.
ASSERT_NO_THROW
(
option
->
writeBoolean
(
true
));
// Finally, check that it has been actually overriden.
ASSERT_NO_THROW
(
value
=
option
->
readBoolean
());
EXPECT_TRUE
(
value
);
}
/// The purpose of this test is to verify that the data field value
/// can be overriden by a new value.
TEST_F
(
OptionCustomTest
,
setUint32Data
)
{
// Create a definition of an option that holds single
// uint32 value.
OptionDefinition
opt_def
(
"OPTION_FOO"
,
1000
,
"uint32"
);
// Create an option and let the data field be initialized
// to default value (do not provide any data buffer).
boost
::
scoped_ptr
<
OptionCustom
>
option
;
ASSERT_NO_THROW
(
option
.
reset
(
new
OptionCustom
(
opt_def
,
Option
::
V6
));
);
ASSERT_TRUE
(
option
);
// The default value for integer data fields is 0.
uint32_t
value
=
0
;
ASSERT_NO_THROW
(
option
->
readInteger
<
uint32_t
>
());
EXPECT_EQ
(
0
,
value
);
// Try to set the data field value to something different
// than 0.
ASSERT_NO_THROW
(
option
->
writeInteger
<
uint32_t
>
(
1234
));
// Verify that it has been set.
ASSERT_NO_THROW
(
value
=
option
->
readInteger
<
uint32_t
>
());
EXPECT_EQ
(
1234
,
value
);
}
// The purpose of this test is to verify that an opton comprising
// single IPv4 address can be created and that this address can
// be overriden by a new value.
TEST_F
(
OptionCustomTest
,
setIpv4AddressData
)
{
OptionDefinition
opt_def
(
"OPTION_FOO"
,
232
,
"ipv4-address"
);
// Create an option and let the data field be initialized
// to default value (do not provide any data buffer).
boost
::
scoped_ptr
<
OptionCustom
>
option
;
ASSERT_NO_THROW
(
option
.
reset
(
new
OptionCustom
(
opt_def
,
Option
::
V4
));
);
ASSERT_TRUE
(
option
);
asiolink
::
IOAddress
address
(
"127.0.0.1"
);
ASSERT_NO_THROW
(
address
=
option
->
readAddress
());
EXPECT_EQ
(
"0.0.0.0"
,
address
.
toText
());
EXPECT_NO_THROW
(
option
->
writeAddress
(
IOAddress
(
"192.168.0.1"
)));
EXPECT_NO_THROW
(
address
=
option
->
readAddress
());
EXPECT_EQ
(
"192.168.0.1"
,
address
.
toText
());
}
// The purpose of this test is to verify that an opton comprising
// single IPv6 address can be created and that this address can
// be overriden by a new value.
TEST_F
(
OptionCustomTest
,
setIpv6AddressData
)
{
OptionDefinition
opt_def
(
"OPTION_FOO"
,
1000
,
"ipv6-address"
);
// Create an option and let the data field be initialized
// to default value (do not provide any data buffer).
boost
::
scoped_ptr
<
OptionCustom
>
option
;
ASSERT_NO_THROW
(
option
.
reset
(
new
OptionCustom
(
opt_def
,
Option
::
V6
));
);
ASSERT_TRUE
(
option
);
asiolink
::
IOAddress
address
(
"::1"
);
ASSERT_NO_THROW
(
address
=
option
->
readAddress
());
EXPECT_EQ
(
"::"
,
address
.
toText
());
EXPECT_NO_THROW
(
option
->
writeAddress
(
IOAddress
(
"2001:db8:1::1"
)));
EXPECT_NO_THROW
(
address
=
option
->
readAddress
());
EXPECT_EQ
(
"2001:db8:1::1"
,
address
.
toText
());
}
// The purpose of this test is to verify that an option comprising
// single string value can be created and that this value
// is initialized to the default value. Also, this test checks that
// this value can be overwritten by a new value.
TEST_F
(
OptionCustomTest
,
setStringData
)
{
OptionDefinition
opt_def
(
"OPTION_FOO"
,
1000
,
"string"
);
// Create an option and let the data field be initialized
// to default value (do not provide any data buffer).
boost
::
scoped_ptr
<
OptionCustom
>
option
;
ASSERT_NO_THROW
(
option
.
reset
(
new
OptionCustom
(
opt_def
,
Option
::
V6
));
);
ASSERT_TRUE
(
option
);
// Get the default value of the option.
std
::
string
value
;
ASSERT_NO_THROW
(
value
=
option
->
readString
());
// By default the string data field is empty.
EXPECT_TRUE
(
value
.
empty
());
// Write some text to this field.
EXPECT_NO_THROW
(
option
->
writeString
(
"hello world"
));
// Check that it has been actually written.
EXPECT_NO_THROW
(
value
=
option
->
readString
());
EXPECT_EQ
(
"hello world"
,
value
);
}
// The purpose of this test is to verify that pack function for
// DHCPv4 custom option works correctly.
TEST_F
(
OptionCustomTest
,
pack4
)
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment