2
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
24
#include "precompiled.hpp"
26
#include "memory/allocation.inline.hpp"
27
#include "memory/resourceArea.hpp"
28
#include "runtime/os.hpp"
29
#include "utilities/istream.hpp"
30
#include "unittest.hpp"
32
template<typename BlockClass>
33
class BlockInputStream : public inputStream {
36
template<typename... Arg>
37
BlockInputStream(Arg... arg)
43
#define EXPECT_MEMEQ(s1, s2, len) \
44
EXPECT_PRED_FORMAT3(CmpHelperMEMEQ, s1, s2, len)
45
// cf. ::testing::internal::CmpHelperSTREQ
47
testing::AssertionResult CmpHelperMEMEQ(const char* s1_expression,
48
const char* s2_expression,
49
const char* len_expression,
50
const char* s1, const char* s2,
52
if (s1 == nullptr || s2 == nullptr) {
53
return testing::internal::CmpHelperEQ(s1_expression, s2_expression,
56
int c = ::memcmp(s1, s2, len);
58
return testing::AssertionSuccess();
60
::std::string str1, str2;
61
for (auto which = 0; which <= 1; which++) {
62
auto s = which ? s1 : s2;
63
auto &str = which ? str1 : str2;
64
std::stringstream buf;
66
for (size_t i = 0; i < len; i++) {
69
case '\0': buf << "\\0"; break;
70
case '\n': buf << "\\n"; break;
71
case '\\': buf << "\\\\"; break;
72
default: buf << c; break;
75
buf << "}[" << len_expression << "=" << len << "]";
78
return testing::internal::CmpHelperSTREQ(s1_expression, s2_expression,
79
str1.c_str(), str2.c_str());
82
static int firstdiff(char* b1, char* b2, int blen) {
83
for (int i = 0; i < blen; i++) {
84
if (b1[i] != b2[i]) return i;
89
static char* get_temp_file(bool VERBOSE, const char* filename) {
90
const char* tmp_dir = os::get_temp_directory();
91
const char* file_sep = os::file_separator();
92
size_t temp_file_len = strlen(tmp_dir) + strlen(file_sep) + strlen(filename) + 28;
93
char* temp_file = NEW_C_HEAP_ARRAY(char, temp_file_len, mtInternal);
94
int ret = jio_snprintf(temp_file, temp_file_len, "%s%spid%d.%s",
96
os::current_process_id(), filename);
97
if (VERBOSE) tty->print_cr("temp_file = %s", temp_file);
101
static const char* get_temp_file(bool VERBOSE) {
102
static const char* temp_file = get_temp_file(VERBOSE, "test_istream");
107
#define LC0(x) ('/' + (((unsigned)(x)+1) % EIGHTY))
108
#define LC(line,col) LC0((col) * (line))
112
static int cases, total, zeroes;
114
#define istream_coverage_mode(mode, a,b,c) \
115
inputStream::coverage_mode(mode, a,b,c)
117
#define istream_coverage_mode(mode, a,b,c)
120
// Fill in a test pattern of ascii characters.
121
// Each line is ncols long, plus a line termination of lelen (1 or 2).
122
// Each character is a fixed, static function of the line and column.
123
// This enables test logic to predict exactly what will be read in each line.
124
static void fill_pattern(bool VERBOSE,
125
char* pat, int patlen, int ncols, int lelen,
126
int& full_lines, int& partial_line,
127
const char* &line_end,
128
const char* &partial_line_end) {
129
full_lines = partial_line = 0;
130
for (int i = 0; i < patlen; i++) {
131
int line = (i / (ncols+lelen)) + 1; // 1-based line number
132
int col = (i % (ncols+lelen)) + 1; // 1-based column number
134
pat[i] = LC(line, col);
136
} else if (col < ncols+lelen) {
137
pat[i] = i == patlen - 1 ? '!' : '%';
140
assert(col == ncols+lelen, "");
147
if (VERBOSE) tty->print_cr("PATTERN=%d+%d[%s]",
148
full_lines, partial_line, pat);
149
for (int i = 0; i < patlen; i++) {
150
assert(pat[i] != '%' || (i+1 < patlen && pat[i+1] == '!'), "");
151
if (pat[i] == '!') pat[i] = '\n';
152
if (pat[i] == '%') pat[i] = '\r';
154
assert(pat[patlen-1] != '\r', "");
156
line_end = (lelen == 2 ? "\r\n" : "\n");
157
int partial_line_bytes = patlen - (full_lines * (ncols + lelen));
158
assert(partial_line_bytes < ncols + lelen, "");
159
partial_line_end = (partial_line_bytes == ncols + 1) ? "\n" : "";
162
static const int MAX_PATLEN = COLS * (COLS-1);
164
static void istream_test_driver(const bool VERBOSE,
168
const bool TEST_SET_POSITION,
169
const bool TEST_PUSH_BACK,
170
const bool TEST_EXPAND_REDUCE) {
171
DEBUG_ONLY( istream_coverage_mode(VERBOSE ? 2 : 1, cases, total, zeroes) );
172
const char* temp_file = get_temp_file(VERBOSE);
174
char pat[MAX_PATLEN+1];
175
int full_lines = 0, partial_line = 0;
176
const char* line_end = "\n";
177
const char* partial_line_end = "";
178
fill_pattern(VERBOSE, pat, patlen, ncols, lelen,
179
full_lines, partial_line,
180
line_end, partial_line_end);
182
char pat2[sizeof(pat)]; // copy of pat to help detect scribbling
183
memcpy(pat2, pat, sizeof(pat));
184
// Make three kinds of stream and test them all.
185
MemoryInput _min(pat2, patlen);
186
inputStream sin(&_min);
188
tty->print("at %llx ", (unsigned long long)(intptr_t)&sin);
192
fileStream tfs(temp_file);
193
guarantee(tfs.is_open(), "cannot open temp file");
194
tfs.write(pat, patlen);
196
BlockInputStream<FileInput> fin(temp_file);
198
tty->print("at %llx ", (unsigned long long)(intptr_t)&fin);
201
BlockInputStream<MemoryInput> min(&pat2[0], patlen);
203
tty->print("at %llx ", (unsigned long long)(intptr_t)&min);
206
inputStream* ins[] = { &sin, &fin, &min };
207
const char* in_names[] = { "sin", "fin", "min" };
208
const char* test_mode = (TEST_SET_POSITION
209
? (!TEST_PUSH_BACK ? "(seek)" : "(seek/push)")
211
? (!TEST_PUSH_BACK ? "(exp/red)" : "(exp/red/push)")
212
: (!TEST_PUSH_BACK ? "(plain)" : "(push)"));
213
for (int which = 0; which < 3; which++) {
214
inputStream& in = *ins[which];
215
const char* in_name = in_names[which];
217
char* lp = (char*)"--";
219
in_name << test_mode \
220
<< " ncols=" << ncols << " lelen=" << lelen \
221
<< " full=" << full_lines << " lineno=" << lineno \
222
<< " [" << lp << "]" << (in.dump("expect"), "")
224
tty->print_cr("testing %s%s patlen=%d ncols=%d full_lines=%d partial_line=%d",
226
patlen, ncols, full_lines, partial_line);
227
int pos_to_set = 0, line_to_set = 1; // for TEST_SET_POSITION only
228
for (int phase = 0; phase <= (TEST_SET_POSITION ? 1 : 0); phase++) {
230
for (; lineno <= full_lines + partial_line; lineno++) {
231
EXPECT_EQ(-1, firstdiff(pat, pat2, patlen + 1));
232
if (VERBOSE) in.dump("!done?");
233
bool done = in.done();
234
EXPECT_TRUE(!done) <<LPEQ;
236
lp = in.current_line();
237
const char* expect_endl =
238
(lineno <= full_lines) ? line_end : partial_line_end;
240
bool verify_lp = true;
242
int actual_lineno = (int) in.lineno();
243
if (VERBOSE) in.dump("CL ");
244
EXPECT_EQ(actual_lineno, lineno) <<LPEQ;
245
int len = (int) in.current_line_length();
246
EXPECT_EQ(len, (int) strlen(lp)) <<LPEQ;
247
int expect_len = ncols;
248
if (lineno > full_lines)
249
expect_len = MIN2(ncols, patlen % (ncols+lelen));
250
EXPECT_EQ(len, expect_len) <<LPEQ;
251
for (int j = 0; j < len; j++) {
252
int lc = LC(lineno, j+1); // 1-based column
253
EXPECT_EQ(lc, lp[j]) <<LPEQ;
255
if (len != expect_len || len != (int)strlen(lp)) {
256
return; // no error cascades please
259
if (VERBOSE) in.dump("next ");
263
for (int done_test = 0; done_test <= 3; done_test++) {
264
if (done_test == 2) in.set_done();
265
lp = in.current_line(); // should be empty line
266
if (VERBOSE) in.dump("done!!");
267
EXPECT_TRUE(lp != nullptr);
268
EXPECT_TRUE(in.done()) <<LPEQ;
269
if (!in.done()) break;
270
EXPECT_EQ((int)in.current_line_length(), 0) <<LPEQ;
271
EXPECT_EQ(strlen(lp), in.current_line_length()) <<LPEQ;
272
bool extra_next = in.next();
273
EXPECT_TRUE(!extra_next) <<LPEQ;
276
// no memory side effects
277
EXPECT_EQ(-1, firstdiff(pat, pat2, patlen + 1));
283
static void istream_test_driver(const bool VERBOSE,
284
const bool TEST_SET_POSITION,
285
const bool TEST_PUSH_BACK,
286
const bool TEST_EXPAND_REDUCE) {
288
int patlen = MAX_PATLEN;
289
const bool SHORT_TEST = false;
290
const int SHORT_NCOLS = 1, SHORT_PATLEN = 37;
291
if (SHORT_TEST) patlen = SHORT_PATLEN;
292
for (int ncols = 0; ncols <= patlen; ncols++) {
294
if (ncols < SHORT_NCOLS) ncols = SHORT_NCOLS;
295
if (ncols > SHORT_NCOLS) break;
296
} else if (ncols > COLS && ncols < patlen - COLS) {
298
if (ncols > patlen - COLS) ncols = (patlen - COLS);
300
for (int lelen = 1; lelen <= 2; lelen++) { // try both kinds of newline
301
istream_test_driver(VERBOSE,
302
patlen, ncols, lelen,
303
TEST_SET_POSITION, TEST_PUSH_BACK, TEST_EXPAND_REDUCE);
308
TEST_VM(istream, basic) {
309
const bool VERBOSE = false;
310
istream_test_driver(VERBOSE, false, false, false);
313
TEST_VM(istream, coverage) {
314
const bool VERBOSE = false;
316
istream_coverage_mode(0, cases, total, zeroes);
317
if (cases == 0) return;
318
if (VERBOSE || zeroes != 0)
319
istream_coverage_mode(-1, cases, total, zeroes);
320
EXPECT_EQ(zeroes, 0) << "zeroes: " << zeroes << "/" << cases;