<commit_before>// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library test_utils;

import 'dart:async';
import 'dart:io';
import 'dart:json' as json;
import 'dart:uri';

import 'package:unittest/unittest.dart';
import '../lib/src/byte_stream.dart';
import '../lib/http.dart' as http;
import '../lib/src/utils.dart';
import 'safe_http_server.dart';

/// The current server instance.
HttpServer _server;

/// The URL for the current server instance.
Uri get serverUrl => Uri.parse('http://localhost:${_server.port}');

/// A dummy URL for constructing requests that won't be sent.
Uri get dummyUrl => Uri.parse('http://dartlang.org/');

/// Starts a new HTTP server.
Future startServer() {
  return SafeHttpServer.bind("127.0.0.1", 0).then((s) {
    _server = s;
    s.listen((request) {
      var path = request.uri.path;
      var response = request.response;

      if (path == '/error') {
        response.statusCode = 400;
        response.contentLength = 0;
        response.close();
        return;
      }

      if (path == '/loop') {
        var n = int.parse(request.uri.query);
        response.statusCode = 302;
        response.headers.set('location',
            serverUrl.resolve('/loop?${n + 1}').toString());
        response.contentLength = 0;
        response.close();
        return;
      }

      if (path == '/redirect') {
        response.statusCode = 302;
        response.headers.set('location', serverUrl.resolve('/').toString());
        response.contentLength = 0;
        response.close();
        return;
      }

      new ByteStream(request).toBytes().then((requestBodyBytes) {
        var outputEncoding;
        var encodingName = request.queryParameters['response-encoding'];
        if (encodingName != null) {
          outputEncoding = requiredEncodingForCharset(encodingName);
        } else {
          outputEncoding = Encoding.ASCII;
        }

        response.headers.contentType =
            new ContentType(
                "application", "json", charset: outputEncoding.name);
        response.headers.set('single', 'value');

        var requestBody;
        if (requestBodyBytes.isEmpty) {
          requestBody = null;
        } else if (request.headers.contentType.charset != null) {
          var encoding = requiredEncodingForCharset(
              request.headers.contentType.charset);
          requestBody = decodeString(requestBodyBytes, encoding);
        } else {
          requestBody = requestBodyBytes;
        }

        var content = {
          'method': request.method,
          'path': request.uri.path,
          'headers': {}
        };
        if (requestBody != null) content['body'] = requestBody;
        request.headers.forEach((name, values) {
          // These headers are automatically generated by dart:io, so we don't
          // want to test them here.
          if (name == 'cookie' || name == 'host') return;

          content['headers'][name] = values;
        });

        var body = json.stringify(content);
        response.contentLength = body.length;
        response.write(body);
        response.close();
      });
    });
  });
}

/// Stops the current HTTP server.
void stopServer() {
  _server.close();
  _server = null;
}

/// Removes eight spaces of leading indentation from a multiline string.
///
/// Note that this is very sensitive to how the literals are styled. They should
/// be:
///     '''
///     Text starts on own line. Lines up with subsequent lines.
///     Lines are indented exactly 8 characters from the left margin.
///     Close is on the same line.'''
///
/// This does nothing if text is only a single line.
// TODO(nweiz): Make this auto-detect the indentation level from the first
// non-whitespace line.
String cleanUpLiteral(String text) {
  var lines = text.split('\n');
  if (lines.length <= 1) return text;

  for (var j = 0; j < lines.length; j++) {
    if (lines[j].length > 8) {
      lines[j] = lines[j].substring(8, lines[j].length);
    } else {
      lines[j] = '';
    }
  }

  return lines.join('\n');
}

// TODO(nweiz): Remove this when issue 9252 is fixed.
/// Asynchronously recursively deletes [dir]. Returns a [Future] that completes
/// when the deletion is done.
Future deleteDir(String dir) =>
  _attemptRetryable(() => new Directory(dir).delete(recursive: true));

/// On Windows, we sometimes get failures where the directory is still in use
/// when we try to do something with it. This is usually because the OS hasn't
/// noticed yet that a process using that directory has closed. To be a bit
/// more resilient, we wait and retry a few times.
///
/// Takes a [callback] which returns a future for the operation being attempted.
/// If that future completes with an error, it will slepp and then [callback]
/// will be invoked again to retry the operation. It will try a few times before
/// giving up.
Future _attemptRetryable(Future callback()) {
  // Only do lame retry logic on Windows.
  if (Platform.operatingSystem != 'windows') return callback();

  var attempts = 0;
  makeAttempt(_) {
    attempts++;
    return callback().catchError((e) {
      if (attempts >= 10) {
        throw 'Could not complete operation. Gave up after $attempts attempts.';
      }

      return new Future.delayed(new Duration(milliseconds: 500))
          .then(makeAttempt);
    });
  }

  return makeAttempt(null);
}

/// A matcher that matches JSON that parses to a value that matches the inner<commit_msg>Provisionally stop working around issues 9252 and 9253.<commit_after>// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library test_utils;

import 'dart:async';
import 'dart:io';
import 'dart:json' as json;
import 'dart:uri';

import 'package:unittest/unittest.dart';
import '../lib/src/byte_stream.dart';
import '../lib/http.dart' as http;
import '../lib/src/utils.dart';
import 'safe_http_server.dart';

/// The current server instance.
HttpServer _server;

/// The URL for the current server instance.
Uri get serverUrl => Uri.parse('http://localhost:${_server.port}');

/// A dummy URL for constructing requests that won't be sent.
Uri get dummyUrl => Uri.parse('http://dartlang.org/');

/// Starts a new HTTP server.
Future startServer() {
  return SafeHttpServer.bind("127.0.0.1", 0).then((s) {
    _server = s;
    s.listen((request) {
      var path = request.uri.path;
      var response = request.response;

      if (path == '/error') {
        response.statusCode = 400;
        response.contentLength = 0;
        response.close();
        return;
      }

      if (path == '/loop') {
        var n = int.parse(request.uri.query);
        response.statusCode = 302;
        response.headers.set('location',
            serverUrl.resolve('/loop?${n + 1}').toString());
        response.contentLength = 0;
        response.close();
        return;
      }

      if (path == '/redirect') {
        response.statusCode = 302;
        response.headers.set('location', serverUrl.resolve('/').toString());
        response.contentLength = 0;
        response.close();
        return;
      }

      new ByteStream(request).toBytes().then((requestBodyBytes) {
        var outputEncoding;
        var encodingName = request.queryParameters['response-encoding'];
        if (encodingName != null) {
          outputEncoding = requiredEncodingForCharset(encodingName);
        } else {
          outputEncoding = Encoding.ASCII;
        }

        response.headers.contentType =
            new ContentType(
                "application", "json", charset: outputEncoding.name);
        response.headers.set('single', 'value');

        var requestBody;
        if (requestBodyBytes.isEmpty) {
          requestBody = null;
        } else if (request.headers.contentType.charset != null) {
          var encoding = requiredEncodingForCharset(
              request.headers.contentType.charset);
          requestBody = decodeString(requestBodyBytes, encoding);
        } else {
          requestBody = requestBodyBytes;
        }

        var content = {
          'method': request.method,
          'path': request.uri.path,
          'headers': {}
        };
        if (requestBody != null) content['body'] = requestBody;
        request.headers.forEach((name, values) {
          // These headers are automatically generated by dart:io, so we don't
          // want to test them here.
          if (name == 'cookie' || name == 'host') return;

          content['headers'][name] = values;
        });

        var body = json.stringify(content);
        response.contentLength = body.length;
        response.write(body);
        response.close();
      });
    });
  });
}

/// Stops the current HTTP server.
void stopServer() {
  _server.close();
  _server = null;
}

/// Removes eight spaces of leading indentation from a multiline string.
///
/// Note that this is very sensitive to how the literals are styled. They should
/// be:
///     '''
///     Text starts on own line. Lines up with subsequent lines.
///     Lines are indented exactly 8 characters from the left margin.
///     Close is on the same line.'''
///
/// This does nothing if text is only a single line.
// TODO(nweiz): Make this auto-detect the indentation level from the first
// non-whitespace line.
String cleanUpLiteral(String text) {
  var lines = text.split('\n');
  if (lines.length <= 1) return text;

  for (var j = 0; j < lines.length; j++) {
    if (lines[j].length > 8) {
      lines[j] = lines[j].substring(8, lines[j].length);
    } else {
      lines[j] = '';
    }
  }

  return lines.join('\n');
}

/// A matcher that matches JSON that parses to a value that matches the inner
{'fraction_non_alphanumeric': 0.12989359566352138, 'fraction_numerical': 0.007628990162617948, 'mean_word_length': 2.4799161718477123, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5783204', 'n_tokens_mistral': 2875, 'n_tokens_neox': 2750, 'n_words': 889}