Boost correctness and Test

Source: Internet
Author: User

The boost. Assert library enhances the original assert Macro during runtime. The static_assert Library provides static assertions (diagnosis during compilation), while the boost. Test Library builds a complete unit test framework.

Assert:
The idea tool provided by boost. Assert is the boost_assert macro, which is similar to the assert macro in the C standard and provides runtime assertions.
# Include <boost/assert. HPP>
Basic usage:
By default, the boost_assert macro is equivalent to the assert macro, and the asserted expression is true, that is
# Define boost_assert (expr) assert (expr)
Example:
# Include <boost/assign. HPP>
Using namespace boost;
Using namespace STD;

Double func (int x)
{
// Macros also use the operator & to add asserted information to the expression. When an asserted fails, specific descriptive text can be provided.
Boost_assert (X! = 0 & "divided by zero ");
Return 1.0/X;
}
Int main ()
{
Func (0 );
System ("pause ");
Return 0;
}

Disable assertion:
If the macro boost_disable_asserts is defined before the header file <boost/assert. HPP>, then boost_assert
It will be defined as (void) 0) and will automatically expire, but the standard assert Macro will not be affected.
Example:
# Include <iostream>
# Define boost_disable_asserts
# Include <boost/assign. HPP>
# Include <cassert>
Using namespace boost;
Using namespace STD;
Double func (int x)
{
Boost_assert (X! = 0 & "divided by zero ");
Cout <"after boost_assert" <Endl;
Assert (X! = 0 & "divided by zero ");
Cout <"after" <Endl;
Return 1.0/X;
}
Int main ()
{
Func (0 );
System ("pause ");
Return 0;
}

Extended usage:
If the macro boost_enable_assert_handler is defined before the header file <boost/assert. HPP>, this will change the boost_assert behavior.
It will no longer be equivalent to assert macros. The assert expression will be evaluated in both Debug and release modes. If the assertion fails, a function that fails to be asserted will call boost :: assertion_failed () -- this is equivalent to providing an error handling handle.
The function assertion_failed () is declared in the boost namespace, but it is specially designed to have no specific implementation. Its declaration is as follows:
Namespace boost
{
Void assertion_failed (char const * expr, char const * function, char const * file, long line );
}
When the assertion_failed () function fails, the boost_assert macro calls the asserted expression string and calls the function name (using boost_current_function). The source file name and row number are passed to the assertion_failed () function for processing () function to handle errors in an appropriate way-usually logging or throwing an exception.
Example:
# Include <iostream>
# Define boost_enable_assert_handler
# Include <boost/format. HPP>
# Include <boost/assert. HPP>
# Include <cassert>
Using namespace boost;
Using namespace STD;
Namespace boost
{
Void assertion_failed (char const * expr, char const * function, char const * file, long line)
{
Boost: Format FMT ("assertion failed! \ N expression: % s \ nfunction: % s \ nfile: % s \ nline: % LD \ n ");
FMT % expr % function % file % line;
Cout <FMT;
}
}
Double func (int x)
{
Boost_assert (X! = 0 & "divided by zero ");
Return 1.0/X;
}
Int main ()
{
Func (0 );
System ("pause ");
Return 0;
}
Boost_assert is useful for handle usage. It is suitable for scenarios where unified error handling methods are required. The most common is function entry parameter check, where the function entry asserted parameters, when a parameter error occurs, the system concatenates an error string, throws a parameter exception class, and terminates the function process.
If you are worried about leaking source code information, you can selectively output error messages or encrypt strings.
The assertion_failed function that throws an exception can be implemented as follows:
Void assertion_failed (...)
{
String STR;
...
Throw STD: invalid_argument (STR );
}

Boost_verify:
Boost_verify and boost_assert have only one difference: the expression of the assertion will be evaluated and useful in the use of assertion operations (not just error checks) and function return value verification.
Example:
# Include <boost/assert. HPP>
...
Int Len;
Boost_verify (LEN = strlen ("123"); // Len evaluated
Note that in the release mode, the program should not depend on its side effects.

Static_assert:
Assert and boost_assert are runtime assertions.
The static_assert library advances the assertion diagnosis time from running to compilation.
# Include <boost/static_assert.hpp>
Usage:
The static_assert library defines the macro boost_static_assert, which is used for the compilation period assertions.
Boost_static_assert uses a complex technique, but it is easy to understand. It is actually a typedef, so no code or data is generated during compilation, there is no impact on the running efficiency-whether it is the debug or release mode.
The most important difference between boost_static_assert and boost_assert is the scope of use. boost_assert (assert) must be a statement that can be executed and can only appear in the function field, boost_static_assert can appear in any position of the program: namespace domain, class domain or function domain.

Demonstration: simple template function my_min. For some purpose, it only supports the short or char type
# Include <iostream>
# Include <boost/static_assert.hpp>
Using namespace boost;
Using namespace STD;
Template <typename T>
T my_min (t a, t B)
{
Boost_static_assert (sizeof (t) <sizeof (INT ));
Return a <B? A: B;
}
Int main ()
{
Cout <my_min (short) 1, (short) 3 );
Cout <my_min (1l, 3l );
System ("pause ");
Return 0;
}
The asserted error information may not be obvious enough, but it can indicate the location of the error and points out the basic direction for resolving the error.
Boost_static_assert is used in the class domain and namespace domain in the same way as in the function domain, for example:
Namespace my_space
{
Class empty_class
{
Boost_static_assert (sizeof (INT)> = 4 );
};
// Static assertions of the namespace domain, which is an "Empty class"
Boost_static_assert (sizeof (empty_class) = 1 );
}
C ++ does not allow the existence of objects in a class with a size of 0. Normally, the "EMPTY class" is inserted by the compiler into a member variable with a char type, make it have a definite size.

Suggestions:
Boost_static_assert is mainly used to verify the compile-time constants or template type parameters in generic programming or template meta-programming. When using boost_static_assert, note that the expression of the assertion must be evaluated during the compilation period.

Test:
The Test Library provides a command line interface-based unit test framework for unit testing. It is also provided with the function of detecting memory leaks, it is more powerful than other unit test libraries. It not only supports simple tests, but also supports comprehensive unit tests, as well as program running monitoring. It is a powerful tool to ensure program correctness.
# Include <boost/test/unit_test.hpp>

Compile the Test Library:
Compile the Test Library. The bjam command is as follows:
Bjam-toolset = msvc-with-test-Build-type = complete stdlib = stlport stage
The Test Library provides the pre-compiled source code file. The header file <boost/test/shortded/unit_test.hpp> contains all the implementation code of the Test Library. Therefore, you need to add the CPP file to the project:
# Define boost_test_main // defines the main test suite, which is the entry to test the main function
# Include <boost/test/Included/unit_test.hpp>
In this way, compile all the test implementation code for testing. The source code files of other test suites still need to contain <boost/test/unit_test.hpp>. However, we should add the macro definition boost_test_included, tell the test database how to use the source code:
# Define boost_test_includeed
# Include <boost/test/unit_test.hpp>
It is equivalent to compiling the test static library in test_main.cpp, while other files only contain the declaration of the Test Library and use the compiled static library directly.

Minimal test suite:
The Test Library provides a minimal test suite, minimal test. You do not need to compile the Test Library in any form, but only need to include the header file <boost/test/minimal. HPP>
# Include <boost/test/minimal. HPP>
It only provides the most basic unit test functions. It is not as powerful as UTF and does not support multiple test cases. It has few test assertions, but is simple and small. It is suitable for beginners and simple tests.
Header file <boost/test/minimal. HPP> has implemented a main (), so you don't have to define your own main (). You only need to implement a test_main () function, which is the real function of minimal test.
The Declaration of the test_main () function is similar to that of the standard main () function;
Int test_main (INT argc, char * argv [])
In the function of test_main (), four test macro can be used,
[1] boost_check (predicate): The asserted test is passed. If the test fails, the program execution is not affected.
[2] boost_require (predicate): The test must pass. Otherwise, the program stops running;
[3] boost_error (Message): an error message is provided, and the program continues to run;
[4] boost_fail (Message): an error message is returned and the program is terminated.
Example: usage of minimal test: To test the format Library:
# Include <iostream>
# Include <boost/test/minimal. HPP>
# Include <boost/format. HPP>
Int test_main (INT argc, char * argv []) // test the main function
{
Using namespace boost;
Format FMT ("% d-% d ");
Boost_check (FMT. Size ()! = 0); // The asserted format object has been initialized.
FMT % 12% 34;
Boost_require (FMT. STR () = "12-34"); // verify the formatting result
System ("pause ");
Boost_error ("demo an error message"); // It does not affect Program Execution
System ("pause ");
FMT. Clear ();
FMT % 12;
Try
{
STD: cout <FMT; // the input parameters are incomplete and an exception is thrown.
}
Catch (...)
{
Boost_fail ("Fatal error, test termination ");
}
System ("pause ");
Return 0;
}
Minimal test is only applicable to unit test demonstrations or small programs.
 
Unit test framework introduction:
The test database provides a strong unit test framework (UTF), which provides a simple and flexible solution for the basic field of software development-unit test.
Advantages:
[1] easy to understand. Anyone can easily build a unit test module.
[2] provides test cases and test suite concepts, and can organize them with any complexity.
[3] provides a wide range of test assertions to handle various situations, including C ++ exceptions.
[4] It is easy to initialize test cases, Test suites or the entire test program;
[5] The test progress can be displayed, which is very useful for large-scale tests.
[6] The test information can be displayed in multiple formats, such as flat files or XML files;
[7] supports command line and can be specified to run any test suite or test case;
[8] There are many more advanced usage methods.
The following describes in detail the components of UTF, first of all, the test assertions, which are the basic tools for unit testing.

Test assertions:
In the test library, test assertions are a group of well-known Macros in a similar usage as boost_assert. If the test fails, the file name, row number, and error message of the error are recorded.
A typical test assertion of the test database is boost_chech_equal in the form of boost_xxx_yyy. The naming rules are as follows:
[1] boost _: Follow the naming rules of the boost library. A macro starts with an uppercase boost.
[2] XXX: assertion level. Warn is a warning. It does not affect the program running or increase the number of errors. Check is a check level. If an assertion fails, it increases the number of errors but does not affect the program running, require is the highest level. If an assertion fails, it will increase the number of errors and terminate the program running. The most common assertion level is check. Warn can be used for testing that does not involve key functions of the program, require can be used only when the assertion fails and the test cannot be continued;
[3] YYY; various types of test assertions, such as equal or unequal assertions, throwing/not throwing exceptions, greater than or less.
Boost_check, boost_require, boost_error, and boost_fail are the most basic test assertions that can be used anywhere, but they should be used as little as possible to ensure universality and other assertions.
The following test assertions are commonly used in the test database:
[1] boost_xxx_equal (L, R); Check L = R. If the test fails, the detailed information is provided. It cannot be used for the comparison of floating point numbers. boost_xxx_close should be used for the equal comparison of floating point numbers;
[2] boost_xxx_ge (L, R): Check L> = R. Likewise, there are gt (L <R), LT (L <R), Le (L <= r) and NE (L! = R), they are used to test various inequality.
[3] boost_xxx_throw (expr, exception): the detection expression expr throws the specified exception.
[4] boost_xxx_no_throw (expr, exception): the detection expression expr does not throw the specified exception.
[5] boost_xxx_message (expr, message): it has the same function as an assertion without the message suffix, but a specified message is provided when the test fails;
[6] boost_test_message (Message): it only outputs the notification information, without any warning or error. It is not displayed by default.

Test Cases and suites:
The test database defines the test program as a test module, which consists of four parts: test installation, test subject, test cleaning, and test runner. The test subject is the actual running part of the test module, the test cases and Test suites are organized into a test tree.
A test case is a function that contains multiple test assertions. It is the smallest unit that can be tested independently. Each test case is independent of each other, errors will not affect other test cases;
To add test cases, You need to register them with UTF. In the test database, you can use manual or automatic methods. Generally, the automatic method is easier to use and you can write test code, the macro boost_auto_test_case is used to create a test case like a declared function. Its definition is as follows:
# Define boost_auto_test_case (test_name)
The macro parameter test_name is the name of the test case, generally starting with T, indicating that the entire name is a test case:
For example:
Boost_auto_test_case (t_case1) // test case Declaration
{
Boost_chech_equal (1, 1 );
...
}
A test suite is a container of test cases. It contains one or more test cases. It can manage a wide variety of test cases by group, share the installation/cleaning code, and better organize test cases, the test suite can be nested without the number of nested layers limit.
The test suite can also be used manually or automatically. Two macros boost_auto_test_suite and boost_auto_test_suite_end are used automatically, which are defined as follows:
# Define boost_auto_test_suite (suite_name)
# Define boost_auto_test_suite_end ()
These two macros must be used in pairs. All test cases between macros belong to this test suite. a c ++ source file can contain any number of test suites, and the test suite can be nested, without depth, the test suite name generally starts with S, for example:
Boost_auto_test_suite (s_suite1) // test suite starts
Boost_auto_test_case (t_case1) // test case Declaration
{
Boost_chech_equal (1, 1 );
...
}
Boost_auto_test_case (t_case2) // test case Declaration
{
Boost_chech_equal (1, 1 );
...
}
Boost_auto_test_suite_end () // test suite end
Any UTF unit test program must have a master test suite, which is the root node of the entire test tree, and other test suites are its child nodes.
You can use macro boost_test_main or boost_test_module to define macro boost_auto_test_suite and boost_auto_test_suite_end in the source file of the macro. All test cases automatically belong to the main test suite.

Test instance:
//////////////////////////////////////// ///////
// Main file
# Include <iostream>
# Define boost_test_main
# Include <boost/test/Included/unit_test.hpp>
Using namespace boost;
//////////////////////////////////////// ///////
// Another CPP File
# Define boost_test_included
# Include <boost/test/unit_test.hpp>
# Include <boost/smart_ptr.hpp>
Using namespace boost;
Boost_auto_test_suite (s_smart_ptr)

Boost_auto_test_case (t_scoped_ptr)
{
Scoped_ptr <int> P (New int (874 ));
Boost_check (P );
Boost_check_equal (* P, 874); // test the unreferenced value.
P. Reset (); // scoped_ptr Reset
Boost_check (P = 0); // NULL pointer
}

Boost_auto_test_case (t_shared_ptr)
{
Shared_ptr <int> P (New int (874 ));
Boost_check (P );
Boost_check_equal (* P, 874); // test the unreferenced value.
Boost_check_equal (P. use_count (), 1); // The reference count is 1.
Shared_ptr <int> P2 = P;
Boost_check_equal (p, P2); // The two shared_ptr must be equal.
Boost_check_equal (p2.use _ count (), 2 );
* P2 = 255;
Boost_check_equal (* P, 255 );
Boost_check_gt (* P, 200 );
}
Boost_auto_test_suite_end ()

Test Fixture:
The concept of "test fixture" in UTF implements automatic test installation and cleaning, like a clip clamped at both ends of the test case and test suite, the test fixture can be used not only for test cases, but also for test kits and unit test globally.
To use a test fixture, you must define a fixture class. It only has constructor and destructor and is used to perform test installation and test cleanup. The basic form is as follows:
Struct test_fixture_name
{
Test_fixture_name (){}
~ Test_fixture_name (){}
};
The fixture class is usually a struct, because it is used by UTF for inheritance, the test suite can use all its Members, of course, the fixture class can also be a standard class, there are private, protection and public members, but in this way the test suite can only access the protection and public members of the jigs.
The fixture class of the specified test case and test suite must use two other macros:
# Define boost_fixture_test_suite (suite_name, F)
# Define boost_fixture_test_case (test_name, F)
Replace the previous boost_auto_test_case and boost_auto_test_suite macros. The second parameter specifies the fixture class to be used.
The jigs can be specified at the test suite level, so that all child kits and test cases in the suite will automatically use the installation and cleanup functions provided by the jigs class, however, you can specify other jigs for the Child kit and test cases without being affected by the upper-layer test suite.
The global test fixture uses another macro boost_global_fixture, which defines the fixture class to be applied to all test suites of the entire Test Module-including the master test suite.
Example: The test object is the assign Library:
//////////////////////////////////
# Include <iostream>
# Define boost_test_main
# Include <boost/test/Included/unit_test.hpp>
Using namespace boost;
///////////////////////////////////
# Include <iostream>
# Define boost_test_included
# Include <boost/test/unit_test.hpp>
# Include <boost/assign. HPP>
Using namespace boost;
Using namespace STD;

// Global test fixture
Struct global_fixture
{
Global_fixture () {cout <"Global Setup \ n ";}
~ Global_fixture () {cout <"Global teardown \ n ";}
};

// Define global Jigs
Boost_global_fixture (global_fixture );

// Test kit fixture
Struct assign_fixture
{
Assign_fixture () {cout <"suit Setup \ n ";}
~ Assign_fixture () {cout <"suit teardown \ n ";}
Vector <int> V; // member variables available for all test cases
};

// Define the jigs at the test suite level
Boost_fixture_test_suite (s_assign, assign_fixture)

Boost_auto_test_case (t_assign1) // test + = Operator
{
Using namespace boost: Assign;
V + = 1, 2, 4;
Boost_check_equal (V. Size (), 4 );
Boost_check_equal (V [2], 3 );
}

Boost_auto_test_case (t_assign2) // test the push_back Function
{
Using namespace boost: Assign;
Push_back (V) (10) (20) (30 );

Boost_check_equal (V. Empty (), false );
Boost_check_lt (V [0], V [1]);
}
Boost_auto_test_suite_end ()

Test log:
Test logs are various text information generated during unit testing, including warnings, errors, and basic information. By default, these test logs are directed to the standard output (stdout ), the test log is different from the test report, which summarizes the test log.
Each test log has a level. Only logs exceeding the permitted level can be output. The UTF log level is from low to high, and the low level is not allowed, however, more advanced logs are not restricted.
These log levels are as follows:
[1] All, output all test logs
[2] success, equivalent to all;
[3] test_suite: only information of the test suite can be run.
[4] Message: only user test information (boost_test_message) can be output );
[5] Warning. Only warning assertions (boost_warn_xxx) can be output)
[6] error: only check and require assertions (boost_check_xxx) can be output)
[7] cpp_exception: Only uncaptured C ++ exception information can be output.
[8] system_error: only non-fatal system errors are allowed.
[9] fatal_error: Only fatal system errors can be output.
[10] Nothing; disable any information output.
By default, the UTF log level is warning, and most unit test-related diagnostic information is output. However, because boost_test_message macro is message-level, its information is not output.

The log level can be changed through the command line parameter of the unit test program described below

Running parameters:
Command line parameters:
The basic format of UTF command line parameters is:
-- Arg_name = arg_value
Both the parameter name and parameter value are case-sensitive, and = both sides and -- the right side cannot have spaces
Common command line parameters:
[1] run_test: Specifies the test case or test suite to run, and uses a slash (/) to access any node in the tree. Wildcards * are supported *;
[2] build_info; outputs the compiler, STL, boost, and other system information during unit testing. The value is Yes/No;
[3] output_format; specifies the output information format. The value can be HRF (readable format) or XML;
[4] log_format: Specify the log information format, value: HRF (readable format)/XML;
[5] log_level: the log level that can be output. The value is all, success, test_sutie, message, warning, error, cpp_exception, system_error, fatal_error, And nothing. The default value is warning;
[6] show_progress; Based on the progress_display component, the Test Progress is displayed. The value is yes/no. UTF cannot display the internal progress of the test case, only the ratio of completed test cases to the total number of test cases can be displayed.
Example:
-- Build_info = yes -- run_test = s_assign/* -- output_format = xml

Function execution monitor:
The Test Library provides a function execution monitor class execution_monitor at the lower layer of the UTF framework. It is used by UTF for unit testing, but can also be used for production code. execution_monitor can monitor the execution of a function, even if an unexpected exception occurs in a function, the program runs normally without being affected. The exception will be processed by execution_monitor in a consistent manner.
Definition source file:
# Include <boost/test/impl/execution_monitor.ipp>
# Include <boost/test/impl/debug. IPP>
Using namespace boost;
Usage:
Execution_monitor can currently monitor functions whose return values are Int or which can be converted to int, and use unit_test: callback0 <int> function objects for packaging. Then, the member functions execute () you can monitor and execute encapsulated functions.
The monitoring execution statement of execution_monitor needs to be embedded in a try-Catch Block. If everything is normal, the function monitored by execution_monitor runs and returns the result as it is not monitored. Otherwise, if uncaptured exceptions, software and hardware signal or trap, and assert assertions under VC occur, execution_monitor will capture this exception and throw a new execution_monitor exception, it stores exception-related information.
Execution_monitor is not a standard library exception. The STD: exception subclass must specify its type in the Catch Block. Otherwise, the exceptions thrown by execution_monitor will not be caught.
Example:
# Include <iostream>
# Define boost_test_included
# Include <boost/test/unit_test.hpp>
# Include <boost/test/execution_monitor.hpp>
# Include <boost/test/utils/basic_cstring/IO. HPP>
# Include <boost/assign. HPP>
Using namespace boost;
Using namespace STD;
Int F ()
{
Cout <"f execute" <Endl;
Throw "A error accoured"; // throw an uncaptured exception
Return 10;
}

Int main // test the main function
{
Execution_monitor em; // declare a monitor object
Try
{
Em.exe cute (unit_test: callback0 <int> (f); // monitoring execution F
}
Catch (execution_exception & E)
{
Cout <"execution_exception" <Endl;
Cout <E. What (). Begin () <Endl; // output exception information
}

System ("pause ");
Return 0;
}

Other usage:
Execution_monitor also provides read/write attributes such as p_timeout and p_auto_start_dbg to set monitor behaviors or detect memory leaks. However, these functions are not completely portable.
Execution_monitor can also be used to handle program exceptions in a unified manner, so that you do not have to write your own error handling code. In this case, the exception type thrown by the program must be a C string, STD :: either string or STD: exception can be processed by execution_exception.
Example: Define the translation function of the exception class and register it in prediction_monitor,
Struct my_error
{
Int err_code; // error code
My_error (int ec): err_code (EC) {}// Constructor
};
Void translate_my_err (const my_error & E) // translation function
{
Cout <"my err =" <E. err_code <Endl;
}
Int F ()
{
Cout <"f execute." <Endl;
Throw my_error (100 );
Return 0;
}

Int main ()
{
Execution_monitor em;
// Use the register_exception_translator function to register an abnormal translation function
Em. register_exception_translator <my_error> (translate_my_err );
Try
{
Em.exe cute (unit_test: callback0 <int> (f ));
}
Catch (const execution_exception & E)
{
Cout <"execution_exception" <Endl;
Cout <E. What (). Begin ();
}
}

Program Execution monitor:
The Test Library provides the program execution Monitor Based on the execution_monitor function execution monitor. It is similar to execution_monitor and monitors the execution of the entire program, convert exceptions in the program to standard error return codes available for the operating system.
The usage of the program execution monitor is similar to minimal test. It only needs to contain a header file and implement cpp_main () with the same signature as main ();
# Include <boost/test/Included/prg_exec_monitor.hpp>
Int cpp_main (INT argc, char * argv []) {...}
Note: cpp_main () must return an integer, which is different from main () and does not have the ability to return 0 by default. The program execution monitor uses a function object to wrap cpp_main (), convert it into a non-argument function object that returns int, and then use execution_monitor to monitor the execution. Therefore, its behavior is basically the same as that of execution_monitor. When cpp_main () when an exception occurs or a non-zero value is returned, the exception information is captured and output to the screen.

Expected test failure:
Sometimes a specific test fails and a small number of assertions are allowed to fail. In this case, you can use the macro boost_auto_test_case_expected_failures. Its declaration is as follows,
# Define boost_auto_test_case_expected_failures (test_name, n)
Use this macro in the test suite to specify the test case name and the number of failures allowed, for example;
Boost_fixture_test_suite (test_suit, fixture)
// Allow two assertions to fail
Boost_auto_test_case_expected_failures (t_case1, 2)
Boost_auto_test_case (t_case1)
{...}
Boost_auto_test_suite_end ()
This function is useful when the program has not completed the functions of all modules. You can first write the unit test code and use boost_auto_test_case_expected_failures to ignore unfinished Function Code tests.

Manually register test cases:
Manual testing allows you to write test functions or accept some test data. You can register UTF with a small amount of code to separate the test code from registration.
For manual registration, you must use the macro boost_test_case and boost_param_test_case to generate the test case class and call the framework: xxx_test_suite (). Add () method.

Test generic code:
UTF can also test template functions and template classes.

Tips for using the Test Library in VC:
In the project option build-event, set post-build and add the command:
"$ (Targetdir) \ Users (targetnamecmd.exe" -- result_code = No -- report_level = no;
In this way, the unit test can be run immediately after the VC compilation is complete, and the test assertions that fail are displayed in the output window can be quickly transferred to the asserted position by double-clicking to improve the test efficiency.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.