X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=tests%2Flib%2Ftest_ctf_writer.c;h=3134b4d2b243045c60f0b193fd6e6fcd37b02be3;hb=10817e06047ab0bfcb7e0e300a817502bbdef497;hp=310aea7f1e5341144997ccbb6cc5048df8aa8989;hpb=39d743710703bb335235d1f9fd5258c2f012640f;p=babeltrace.git diff --git a/tests/lib/test_ctf_writer.c b/tests/lib/test_ctf_writer.c index 310aea7f..3134b4d2 100644 --- a/tests/lib/test_ctf_writer.c +++ b/tests/lib/test_ctf_writer.c @@ -39,12 +39,21 @@ #include #include #include "tap/tap.h" +#include +#include #define METADATA_LINE_SIZE 512 #define SEQUENCE_TEST_LENGTH 10 #define PACKET_RESIZE_TEST_LENGTH 100000 -static uint64_t current_time; +#define DEFAULT_CLOCK_FREQ 1000000000 +#define DEFAULT_CLOCK_PRECISION 1 +#define DEFAULT_CLOCK_OFFSET 0 +#define DEFAULT_CLOCK_OFFSET_S 0 +#define DEFAULT_CLOCK_IS_ABSOLUTE 0 +#define DEFAULT_CLOCK_TIME 0 + +static uint64_t current_time = 42; void validate_metadata(char *parser_path, char *metadata_path) { @@ -100,7 +109,7 @@ void validate_metadata(char *parser_path, char *metadata_path) result: ok(ret == 0, "Metadata string is valid"); - if (ret && metadata_fd > 0 && parser_output_fd > 0) { + if (ret && metadata_fd >= 0 && parser_output_fd >= 0) { char *line; size_t len = METADATA_LINE_SIZE; FILE *metadata_fp = NULL, *parser_output_fp = NULL; @@ -110,12 +119,14 @@ result: perror("fdopen on metadata_fd"); goto close_fp; } + metadata_fd = -1; parser_output_fp = fdopen(parser_output_fd, "r"); if (!parser_output_fp) { perror("fdopen on parser_output_fd"); goto close_fp; } + parser_output_fd = -1; line = malloc(len); if (!line) { @@ -136,12 +147,28 @@ result: free(line); close_fp: - fclose(metadata_fp); - fclose(parser_output_fp); + if (metadata_fp) { + if (fclose(metadata_fp)) { + diag("fclose failure"); + } + } + if (parser_output_fp) { + if (fclose(parser_output_fp)) { + diag("fclose failure"); + } + } } - close(parser_output_fd); - close(metadata_fd); + if (parser_output_fd >= 0) { + if (close(parser_output_fd)) { + diag("close error"); + } + } + if (metadata_fd >= 0) { + if (close(metadata_fd)) { + diag("close error"); + } + } } void validate_trace(char *parser_path, char *trace_path) @@ -189,7 +216,7 @@ void validate_trace(char *parser_path, char *trace_path) result: ok(ret == 0, "Babeltrace could read the resulting trace"); - if (ret && babeltrace_output_fd > 0) { + if (ret && babeltrace_output_fd >= 0) { char *line; size_t len = METADATA_LINE_SIZE; FILE *babeltrace_output_fp = NULL; @@ -199,8 +226,12 @@ result: perror("fdopen on babeltrace_output_fd"); goto close_fp; } + babeltrace_output_fd = -1; line = malloc(len); + if (!line) { + diag("malloc error"); + } rewind(babeltrace_output_fp); while (getline(&line, &len, babeltrace_output_fp) > 0) { diag("%s", line); @@ -208,10 +239,18 @@ result: free(line); close_fp: - fclose(babeltrace_output_fp); + if (babeltrace_output_fp) { + if (fclose(babeltrace_output_fp)) { + diag("fclose error"); + } + } } - close(babeltrace_output_fd); + if (babeltrace_output_fd >= 0) { + if (close(babeltrace_output_fd)) { + diag("close error"); + } + } } void append_simple_event(struct bt_ctf_stream_class *stream_class, @@ -224,13 +263,36 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class, bt_ctf_field_type_integer_create(12); struct bt_ctf_field_type *float_type = bt_ctf_field_type_floating_point_create(); + struct bt_ctf_field_type *enum_type = + bt_ctf_field_type_enumeration_create(uint_12_type); struct bt_ctf_event *simple_event; struct bt_ctf_field *integer_field; struct bt_ctf_field *float_field; + struct bt_ctf_field *enum_field; + struct bt_ctf_field *enum_container_field; + const char *mapping_name_test = "truie"; + const char *mapping_name; + const double double_test_value = 3.1415; + double ret_double; bt_ctf_field_type_set_alignment(float_type, 32); bt_ctf_field_type_floating_point_set_exponent_digits(float_type, 11); bt_ctf_field_type_floating_point_set_mantissa_digits(float_type, 53); + + ok(bt_ctf_field_type_enumeration_add_mapping(enum_type, + "escaping; \"test\"", 0, 0) == 0, + "Accept enumeration mapping strings containing quotes"); + ok(bt_ctf_field_type_enumeration_add_mapping(enum_type, + "\tanother \'escaping\'\n test\"", 1, 4) == 0, + "Accept enumeration mapping strings containing special characters"); + ok(bt_ctf_field_type_enumeration_add_mapping(enum_type, + "event clock int float", 5, 22) == 0, + "Accept enumeration mapping strings containing reserved keywords"); + bt_ctf_field_type_enumeration_add_mapping(enum_type, + mapping_name_test, 42, 42); + ok(bt_ctf_event_class_add_field(simple_event_class, enum_type, + "enum_field") == 0, "Add enumeration field to event"); + ok(uint_12_type, "Create an unsigned integer type"); bt_ctf_event_class_add_field(simple_event_class, uint_12_type, "integer_field"); @@ -250,7 +312,31 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class, integer_field) == 0, "Use bt_ctf_event_set_payload to set a manually allocated field"); float_field = bt_ctf_event_get_payload(simple_event, "float_field"); - bt_ctf_field_floating_point_set_value(float_field, 3.1415); + ok(bt_ctf_field_floating_point_get_value(float_field, &ret_double), + "bt_ctf_field_floating_point_get_value fails on an unset float field"); + bt_ctf_field_floating_point_set_value(float_field, double_test_value); + ok(bt_ctf_field_floating_point_get_value(NULL, &ret_double), + "bt_ctf_field_floating_point_get_value properly handles a NULL field"); + ok(bt_ctf_field_floating_point_get_value(float_field, NULL), + "bt_ctf_field_floating_point_get_value properly handles a NULL return value pointer"); + ok(!bt_ctf_field_floating_point_get_value(float_field, &ret_double), + "bt_ctf_field_floating_point_get_value returns a double value"); + ok(fabs(ret_double - double_test_value) <= DBL_EPSILON, + "bt_ctf_field_floating_point_get_value returns a correct value"); + + enum_field = bt_ctf_field_create(enum_type); + mapping_name = bt_ctf_field_enumeration_get_mapping_name(NULL); + ok(!mapping_name, "bt_ctf_field_enumeration_get_mapping_name handles NULL correctly"); + mapping_name = bt_ctf_field_enumeration_get_mapping_name(enum_field); + ok(!mapping_name, "bt_ctf_field_enumeration_get_mapping_name returns NULL if the enumeration's container field is unset"); + enum_container_field = bt_ctf_field_enumeration_get_container( + enum_field); + ok(bt_ctf_field_unsigned_integer_set_value( + enum_container_field, 42) == 0, + "Set enumeration container value"); + mapping_name = bt_ctf_field_enumeration_get_mapping_name(enum_field); + ok(!strcmp(mapping_name, mapping_name_test), "bt_ctf_field_enumeration_get_mapping_name returns the correct mapping name"); + bt_ctf_event_set_payload(simple_event, "enum_field", enum_field); ok(bt_ctf_clock_set_time(clock, current_time) == 0, "Set clock time"); @@ -264,14 +350,18 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class, bt_ctf_event_put(simple_event); bt_ctf_field_type_put(uint_12_type); bt_ctf_field_type_put(float_type); + bt_ctf_field_type_put(enum_type); bt_ctf_field_put(integer_field); bt_ctf_field_put(float_field); + bt_ctf_field_put(enum_field); + bt_ctf_field_put(enum_container_field); } void append_complex_event(struct bt_ctf_stream_class *stream_class, struct bt_ctf_stream *stream, struct bt_ctf_clock *clock) { int i; + const char *test_string = "Test string"; struct bt_ctf_field_type *uint_35_type = bt_ctf_field_type_integer_create(35); struct bt_ctf_field_type *int_16_type = @@ -295,7 +385,10 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class, struct bt_ctf_field *uint_35_field, *int_16_field, *a_string_field, *inner_structure_field, *complex_structure_field, *a_sequence_field, *enum_variant_field, *enum_container_field, - *variant_field; + *variant_field, *ret_field; + int64_t ret_signed_int; + uint64_t ret_unsigned_int; + const char *ret_string; bt_ctf_field_type_set_alignment(int_16_type, 32); bt_ctf_field_type_integer_set_signed(int_16_type, 1); @@ -363,16 +456,55 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class, ok(event, "Instanciate a complex event"); uint_35_field = bt_ctf_event_get_payload(event, "uint_35"); + if (!uint_35_field) + printf("uint_35_field is NULL\n"); ok(uint_35_field, "Use bt_ctf_event_get_payload to get a field instance "); bt_ctf_field_unsigned_integer_set_value(uint_35_field, 0x0DDF00D); + ok(bt_ctf_field_unsigned_integer_get_value(NULL, &ret_unsigned_int) == -1, + "bt_ctf_field_unsigned_integer_get_value properly properly handles a NULL field."); + ok(bt_ctf_field_unsigned_integer_get_value(uint_35_field, NULL) == -1, + "bt_ctf_field_unsigned_integer_get_value properly handles a NULL return value"); + ok(bt_ctf_field_unsigned_integer_get_value(uint_35_field, + &ret_unsigned_int) == 0, + "bt_ctf_field_unsigned_integer_get_value succeeds after setting a value"); + ok(ret_unsigned_int == 0x0DDF00D, + "bt_ctf_field_unsigned_integer_get_value returns the correct value"); + ok(bt_ctf_field_signed_integer_get_value(uint_35_field, + &ret_signed_int) == -1, + "bt_ctf_field_signed_integer_get_value fails on an unsigned field"); bt_ctf_field_put(uint_35_field); int_16_field = bt_ctf_event_get_payload(event, "int_16"); bt_ctf_field_signed_integer_set_value(int_16_field, -12345); + ok(bt_ctf_field_signed_integer_get_value(NULL, &ret_signed_int) == -1, + "bt_ctf_field_signed_integer_get_value properly handles a NULL field"); + ok(bt_ctf_field_signed_integer_get_value(int_16_field, NULL) == -1, + "bt_ctf_field_signed_integer_get_value properly handles a NULL return value"); + ok(bt_ctf_field_signed_integer_get_value(int_16_field, + &ret_signed_int) == 0, + "bt_ctf_field_signed_integer_get_value succeeds after setting a value"); + ok(ret_signed_int == -12345, + "bt_ctf_field_signed_integer_get_value returns the correct value"); + ok(bt_ctf_field_unsigned_integer_get_value(int_16_field, + &ret_unsigned_int) == -1, + "bt_ctf_field_unsigned_integer_get_value fails on a signed field"); bt_ctf_field_put(int_16_field); complex_structure_field = bt_ctf_event_get_payload(event, "complex_structure"); + + ok(bt_ctf_field_structure_get_field_by_index(NULL, 0) == NULL, + "bt_ctf_field_structure_get_field_by_index handles NULL correctly"); + ok(bt_ctf_field_structure_get_field_by_index(NULL, 9) == NULL, + "bt_ctf_field_structure_get_field_by_index handles an invalid index correctly"); + inner_structure_field = bt_ctf_field_structure_get_field_by_index( + complex_structure_field, 3); + ret_field_type = bt_ctf_field_get_type(inner_structure_field); + bt_ctf_field_put(inner_structure_field); + ok(ret_field_type == inner_structure_type, + "bt_ctf_field_structure_get_field_by_index returns a correct field"); + bt_ctf_field_type_put(ret_field_type); + inner_structure_field = bt_ctf_field_structure_get_field( complex_structure_field, "inner_structure"); a_string_field = bt_ctf_field_structure_get_field( @@ -393,12 +525,28 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class, enum_variant_field); bt_ctf_field_signed_integer_set_value(int_16_field, -200); bt_ctf_field_put(int_16_field); + ok(!bt_ctf_field_string_get_value(a_string_field), + "bt_ctf_field_string_get_value returns NULL on an unset field"); bt_ctf_field_string_set_value(a_string_field, - "Test string"); + test_string); + ok(!bt_ctf_field_string_get_value(NULL), + "bt_ctf_field_string_get_value correctly handles NULL"); + ret_string = bt_ctf_field_string_get_value(a_string_field); + ok(ret_string, "bt_ctf_field_string_get_value returns a string"); + ok(!strcmp(ret_string, test_string), + "bt_ctf_field_string_get_value returns a correct value"); bt_ctf_field_unsigned_integer_set_value(uint_35_field, SEQUENCE_TEST_LENGTH); + + ok(bt_ctf_field_sequence_get_length(a_sequence_field) == NULL, + "bt_ctf_field_sequence_get_length returns NULL when length is unset"); ok(bt_ctf_field_sequence_set_length(a_sequence_field, uint_35_field) == 0, "Set a sequence field's length"); + ret_field = bt_ctf_field_sequence_get_length(a_sequence_field); + ok(ret_field == uint_35_field, + "bt_ctf_field_sequence_get_length returns the correct length field"); + ok(bt_ctf_field_sequence_get_length(NULL) == NULL, + "bt_ctf_field_sequence_get_length properly handles NULL"); for (i = 0; i < SEQUENCE_TEST_LENGTH; i++) { int_16_field = bt_ctf_field_sequence_get_field( @@ -421,6 +569,7 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class, bt_ctf_field_put(enum_variant_field); bt_ctf_field_put(enum_container_field); bt_ctf_field_put(variant_field); + bt_ctf_field_put(ret_field); bt_ctf_field_type_put(uint_35_type); bt_ctf_field_type_put(int_16_type); bt_ctf_field_type_put(string_type); @@ -439,6 +588,7 @@ void type_field_tests() struct bt_ctf_field *uint_12; struct bt_ctf_field *int_16; struct bt_ctf_field *string; + struct bt_ctf_field *enumeration; struct bt_ctf_field_type *composite_structure_type; struct bt_ctf_field_type *structure_seq_type; struct bt_ctf_field_type *string_type; @@ -447,6 +597,13 @@ void type_field_tests() struct bt_ctf_field_type *int_16_type; struct bt_ctf_field_type *uint_12_type = bt_ctf_field_type_integer_create(12); + struct bt_ctf_field_type *enumeration_type; + struct bt_ctf_field_type *enumeration_sequence_type; + struct bt_ctf_field_type *enumeration_array_type; + struct bt_ctf_field_type *returned_type; + + returned_type = bt_ctf_field_get_type(NULL); + ok(!returned_type, "bt_ctf_field_get_type handles NULL correctly"); ok(uint_12_type, "Create an unsigned integer type"); ok(bt_ctf_field_type_integer_set_base(uint_12_type, @@ -510,6 +667,10 @@ void type_field_tests() ok(int_16, "Instanciate a signed 16-bit integer"); uint_12 = bt_ctf_field_create(uint_12_type); ok(uint_12, "Instanciate an unsigned 12-bit integer"); + returned_type = bt_ctf_field_get_type(int_16); + ok(returned_type == int_16_type, + "bt_ctf_field_get_type returns the correct type"); + bt_ctf_field_type_put(returned_type); /* Can't modify types after instanciating them */ ok(bt_ctf_field_type_integer_set_base(uint_12_type, @@ -548,9 +709,28 @@ void type_field_tests() ok(bt_ctf_field_string_set_value(string, "A value") == 0, "Set a string's value"); + enumeration_type = bt_ctf_field_type_enumeration_create(uint_12_type); + ok(enumeration_type, + "Create an enumeration type with an unsigned 12-bit integer as container"); + enumeration_sequence_type = bt_ctf_field_type_sequence_create( + enumeration_type, "count"); + ok(!enumeration_sequence_type, + "Check enumeration types are validated when creating a sequence"); + enumeration_array_type = bt_ctf_field_type_array_create( + enumeration_type, 10); + ok(!enumeration_array_type, + "Check enumeration types are validated when creating an array"); + ok(bt_ctf_field_type_structure_add_field(composite_structure_type, + enumeration_type, "enumeration") == 0, + "Check enumeration types are validated when adding them as structure members"); + enumeration = bt_ctf_field_create(enumeration_type); + ok(!enumeration, + "Check enumeration types are validated before instantiation"); + bt_ctf_field_put(string); bt_ctf_field_put(uint_12); bt_ctf_field_put(int_16); + bt_ctf_field_put(enumeration); bt_ctf_field_type_put(composite_structure_type); bt_ctf_field_type_put(structure_seq_type); bt_ctf_field_type_put(string_type); @@ -558,6 +738,9 @@ void type_field_tests() bt_ctf_field_type_put(uint_8_type); bt_ctf_field_type_put(int_16_type); bt_ctf_field_type_put(uint_12_type); + bt_ctf_field_type_put(enumeration_type); + bt_ctf_field_type_put(enumeration_sequence_type); + bt_ctf_field_type_put(enumeration_array_type); } void packet_resize_test(struct bt_ctf_stream_class *stream_class, @@ -625,10 +808,13 @@ int main(int argc, char **argv) char metadata_path[sizeof(trace_path) + 9]; const char *clock_name = "test_clock"; const char *clock_description = "This is a test clock"; - const uint64_t frequency = 1000000000; + const char *returned_clock_name; + const char *returned_clock_description; + const uint64_t frequency = 1123456789; const uint64_t offset_s = 1351530929945824323; const uint64_t offset = 1234567; const uint64_t precision = 10; + const int is_absolute = 0xFF; char *metadata_string; struct bt_ctf_writer *writer; struct utsname name; @@ -692,27 +878,105 @@ int main(int argc, char **argv) name.machine); /* Define a clock and add it to the trace */ - ok(bt_ctf_clock_create("signed") == NULL, "Illegal clock name rejected"); + ok(bt_ctf_clock_create("signed") == NULL, + "Illegal clock name rejected"); ok(bt_ctf_clock_create(NULL) == NULL, "NULL clock name rejected"); clock = bt_ctf_clock_create(clock_name); ok(clock, "Clock created sucessfully"); - bt_ctf_clock_set_description(clock, clock_description); - + returned_clock_name = bt_ctf_clock_get_name(clock); + ok(returned_clock_name, "bt_ctf_clock_get_name returns a clock name"); + ok(strcmp(returned_clock_name, clock_name) == 0, + "Returned clock name is valid"); + + returned_clock_description = bt_ctf_clock_get_description(clock); + ok(!returned_clock_description, "bt_ctf_clock_get_description returns NULL on an unset description"); + ok(bt_ctf_clock_set_description(clock, clock_description) == 0, + "Clock description set successfully"); + + returned_clock_description = bt_ctf_clock_get_description(clock); + ok(returned_clock_description, + "bt_ctf_clock_get_description returns a description."); + ok(strcmp(returned_clock_description, clock_description) == 0, + "Returned clock description is valid"); + + ok(bt_ctf_clock_get_frequency(clock) == DEFAULT_CLOCK_FREQ, + "bt_ctf_clock_get_frequency returns the correct default frequency"); ok(bt_ctf_clock_set_frequency(clock, frequency) == 0, "Set clock frequency"); + ok(bt_ctf_clock_get_frequency(clock) == frequency, + "bt_ctf_clock_get_frequency returns the correct frequency once it is set"); + + ok(bt_ctf_clock_get_offset_s(clock) == DEFAULT_CLOCK_OFFSET_S, + "bt_ctf_clock_get_offset_s returns the correct default offset (in seconds)"); ok(bt_ctf_clock_set_offset_s(clock, offset_s) == 0, "Set clock offset (seconds)"); + ok(bt_ctf_clock_get_offset_s(clock) == offset_s, + "bt_ctf_clock_get_offset_s returns the correct default offset (in seconds) once it is set"); + + ok(bt_ctf_clock_get_offset(clock) == DEFAULT_CLOCK_OFFSET, + "bt_ctf_clock_get_frequency returns the correct default offset (in ticks)"); ok(bt_ctf_clock_set_offset(clock, offset) == 0, "Set clock offset"); + ok(bt_ctf_clock_get_offset(clock) == offset, + "bt_ctf_clock_get_frequency returns the correct default offset (in ticks) once it is set"); + + ok(bt_ctf_clock_get_precision(clock) == DEFAULT_CLOCK_PRECISION, + "bt_ctf_clock_get_precision returns the correct default precision"); ok(bt_ctf_clock_set_precision(clock, precision) == 0, "Set clock precision"); - ok(bt_ctf_clock_set_is_absolute(clock, 0xFF) == 0, + ok(bt_ctf_clock_get_precision(clock) == precision, + "bt_ctf_clock_get_precision returns the correct precision once it is set"); + + ok(bt_ctf_clock_get_is_absolute(clock) == DEFAULT_CLOCK_IS_ABSOLUTE, + "bt_ctf_clock_get_precision returns the correct default is_absolute attribute"); + ok(bt_ctf_clock_set_is_absolute(clock, is_absolute) == 0, "Set clock absolute property"); + ok(bt_ctf_clock_get_is_absolute(clock) == !!is_absolute, + "bt_ctf_clock_get_precision returns the correct is_absolute attribute once it is set"); + + ok(bt_ctf_clock_get_time(clock) == DEFAULT_CLOCK_TIME, + "bt_ctf_clock_get_time returns the correct default time"); + ok(bt_ctf_clock_set_time(clock, current_time) == 0, + "Set clock time"); + ok(bt_ctf_clock_get_time(clock) == current_time, + "bt_ctf_clock_get_time returns the correct time once it is set"); ok(bt_ctf_writer_add_clock(writer, clock) == 0, "Add clock to writer instance"); ok(bt_ctf_writer_add_clock(writer, clock), "Verify a clock can't be added twice to a writer instance"); + ok(!bt_ctf_clock_get_name(NULL), + "bt_ctf_clock_get_name correctly handles NULL"); + ok(!bt_ctf_clock_get_description(NULL), + "bt_ctf_clock_get_description correctly handles NULL"); + ok(bt_ctf_clock_get_frequency(NULL) == -1ULL, + "bt_ctf_clock_get_frequency correctly handles NULL"); + ok(bt_ctf_clock_get_precision(NULL) == -1ULL, + "bt_ctf_clock_get_precision correctly handles NULL"); + ok(bt_ctf_clock_get_offset_s(NULL) == -1ULL, + "bt_ctf_clock_get_offset_s correctly handles NULL"); + ok(bt_ctf_clock_get_offset(NULL) == -1ULL, + "bt_ctf_clock_get_offset correctly handles NULL"); + ok(bt_ctf_clock_get_is_absolute(NULL) == -1, + "bt_ctf_clock_get_is_absolute correctly handles NULL"); + ok(bt_ctf_clock_get_time(NULL) == -1ULL, + "bt_ctf_clock_get_time correctly handles NULL"); + + ok(bt_ctf_clock_set_description(NULL, NULL) == -1, + "bt_ctf_clock_set_description correctly handles NULL clock"); + ok(bt_ctf_clock_set_frequency(NULL, frequency) == -1, + "bt_ctf_clock_set_frequency correctly handles NULL clock"); + ok(bt_ctf_clock_set_precision(NULL, precision) == -1, + "bt_ctf_clock_get_precision correctly handles NULL clock"); + ok(bt_ctf_clock_set_offset_s(NULL, offset_s) == -1, + "bt_ctf_clock_set_offset_s correctly handles NULL clock"); + ok(bt_ctf_clock_set_offset(NULL, offset) == -1, + "bt_ctf_clock_set_offset correctly handles NULL clock"); + ok(bt_ctf_clock_set_is_absolute(NULL, is_absolute) == -1, + "bt_ctf_clock_set_is_absolute correctly handles NULL clock"); + ok(bt_ctf_clock_set_time(NULL, current_time) == -1, + "bt_ctf_clock_set_time correctly handles NULL clock"); + /* Define a stream class */ stream_class = bt_ctf_stream_class_create("test_stream"); ok(stream_class, "Create stream class");