jdk

Форк
0
/
test_istream.cpp 
322 строки · 11.6 Кб
1
/*
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.
4
 *
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.
8
 *
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).
14
 *
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.
18
 *
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
21
 * questions.
22
 */
23

24
#include "precompiled.hpp"
25
#include "jvm.h"
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"
31

32
template<typename BlockClass>
33
class BlockInputStream : public inputStream {
34
  BlockClass _input;
35
 public:
36
  template<typename... Arg>
37
  BlockInputStream(Arg... arg)
38
    : _input(arg...) {
39
    set_input(&_input);
40
  }
41
};
42

43
#define EXPECT_MEMEQ(s1, s2, len) \
44
  EXPECT_PRED_FORMAT3(CmpHelperMEMEQ, s1, s2, len)
45
// cf. ::testing::internal::CmpHelperSTREQ
46

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,
51
                                        size_t len) {
52
  if (s1 == nullptr || s2 == nullptr) {
53
    return testing::internal::CmpHelperEQ(s1_expression, s2_expression,
54
                                          s1, s2);
55
  }
56
  int c = ::memcmp(s1, s2, len);
57
  if (c == 0) {
58
    return testing::AssertionSuccess();
59
  }
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;
65
    buf << "{";
66
    for (size_t i = 0; i < len; i++) {
67
      char c = s[i];
68
      switch (c) {
69
      case '\0':  buf << "\\0"; break;
70
      case '\n':  buf << "\\n"; break;
71
      case '\\':  buf << "\\\\"; break;
72
      default:    buf << c; break;
73
      }
74
    }
75
    buf << "}[" << len_expression << "=" << len << "]";
76
    str = buf.str();
77
  }
78
  return testing::internal::CmpHelperSTREQ(s1_expression, s2_expression,
79
                                           str1.c_str(), str2.c_str());
80
}
81

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;
85
  }
86
  return -1;
87
}
88

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",
95
                         tmp_dir, file_sep,
96
                         os::current_process_id(), filename);
97
  if (VERBOSE)  tty->print_cr("temp_file = %s", temp_file);
98
  return temp_file;
99
}
100

101
static const char* get_temp_file(bool VERBOSE) {
102
  static const char* temp_file = get_temp_file(VERBOSE, "test_istream");
103
  return temp_file;
104
}
105

106
#define EIGHTY 80
107
#define LC0(x)     ('/' + (((unsigned)(x)+1) % EIGHTY))
108
#define LC(line,col)  LC0((col) * (line))
109

110
#define COLS 30
111

112
static int cases, total, zeroes;
113
#ifdef ASSERT
114
#define istream_coverage_mode(mode, a,b,c) \
115
  inputStream::coverage_mode(mode, a,b,c)
116
#else
117
#define istream_coverage_mode(mode, a,b,c)
118
#endif
119

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
133
    if (col <= ncols) {
134
      pat[i] = LC(line, col);
135
      partial_line = 1;
136
    } else if (col < ncols+lelen) {
137
      pat[i] = i == patlen - 1 ? '!' : '%';
138
      partial_line = 1;
139
    } else {
140
      assert(col == ncols+lelen, "");
141
      pat[i] = '!';
142
      full_lines++;
143
      partial_line = 0;
144
    }
145
  }
146
  pat[patlen] = '\0';
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';
153
  }
154
  assert(pat[patlen-1] != '\r', "");
155

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" : "";
160
}
161

162
static const int MAX_PATLEN = COLS * (COLS-1);
163

164
static void istream_test_driver(const bool VERBOSE,
165
                                const int patlen,
166
                                const int ncols,
167
                                const int lelen,
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);
173
  unlink(temp_file);
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);
181

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);
187
  if (VERBOSE) {
188
    tty->print("at %llx ", (unsigned long long)(intptr_t)&sin);
189
    sin.dump("sin");
190
  }
191
  {
192
    fileStream tfs(temp_file);
193
    guarantee(tfs.is_open(), "cannot open temp file");
194
    tfs.write(pat, patlen);
195
  }
196
  BlockInputStream<FileInput> fin(temp_file);
197
  if (VERBOSE) {
198
    tty->print("at %llx ", (unsigned long long)(intptr_t)&fin);
199
    fin.dump("fin");
200
  }
201
  BlockInputStream<MemoryInput> min(&pat2[0], patlen);
202
  if (VERBOSE) {
203
    tty->print("at %llx ", (unsigned long long)(intptr_t)&min);
204
    sin.dump("min");
205
  }
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)")
210
                           : TEST_EXPAND_REDUCE
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];
216
    int lineno;
217
    char* lp = (char*)"--";
218
#define LPEQ                                                    \
219
    in_name << test_mode                                        \
220
            << " ncols=" << ncols << " lelen=" << lelen         \
221
            << " full=" << full_lines << " lineno=" << lineno   \
222
            << " [" << lp << "]" << (in.dump("expect"), "")
223
    if (VERBOSE)
224
      tty->print_cr("testing %s%s patlen=%d ncols=%d full_lines=%d partial_line=%d",
225
                    in_name, test_mode,
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++) {
229
      lineno = 1;
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;
235
        if (done)  break;
236
        lp = in.current_line();
237
        const char* expect_endl =
238
          (lineno <= full_lines) ? line_end : partial_line_end;
239

240
        bool verify_lp = true;
241
        if (verify_lp) {
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;
254
          }
255
          if (len != expect_len || len != (int)strlen(lp)) {
256
            return;  // no error cascades please
257
          }
258
        }
259
        if (VERBOSE)  in.dump("next  ");
260
        in.next();
261
      }
262

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;
274
      }
275

276
      // no memory side effects
277
      EXPECT_EQ(-1, firstdiff(pat, pat2, patlen + 1));
278
    }
279
  }
280
  unlink(temp_file);
281
}
282

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) {
287
  ResourceMark rm;
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++) {
293
    if (SHORT_TEST) {
294
      if (ncols < SHORT_NCOLS)  ncols = SHORT_NCOLS;
295
      if (ncols > SHORT_NCOLS)  break;
296
    } else if (ncols > COLS && ncols < patlen - COLS) {
297
      ncols += ncols / 7;
298
      if (ncols > patlen - COLS)  ncols = (patlen - COLS);
299
    }
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);
304
    }
305
  }
306
}
307

308
TEST_VM(istream, basic) {
309
  const bool VERBOSE = false;
310
  istream_test_driver(VERBOSE, false, false, false);
311
}
312

313
TEST_VM(istream, coverage) {
314
  const bool VERBOSE = false;
315
#ifdef ASSERT
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;
321
#endif //ASSERT
322
}
323

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.