summaryrefslogtreecommitdiff
path: root/tools/integration_tests.py
blob: 6ce4f3d8b540cd5c521b2881ee173db16656c67d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
# Given a deno executable, this script executes several integration tests with
# it. The tests are stored in /tests/ and each is specified in a .yaml file
# where a description, command line, and output are specified.  Optionally an
# exit code can be specified.
#
# Usage: integration_tests.py [path to deno executable]
import os
import re
import subprocess

import http_server
from test_util import DenoTestCase, run_tests
from util import root_path, tests_path, pattern_match, rmtree


def strip_ansi_codes(s):
    ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
    return ansi_escape.sub('', s)


def read_test(file_name):
    with open(file_name, "r") as f:
        test_file = f.read()
    lines = test_file.splitlines()
    test_dict = {}
    for line in lines:
        if line.strip().startswith("#"):
            # skip comments
            continue
        key, value = re.split(r":\s+", line)
        test_dict[key] = value
    return test_dict


def str2bool(v):
    if v == "true":
        return True
    elif v == "false":
        return False
    else:
        raise ValueError("Bad boolean value")


class TestIntegrations(DenoTestCase):
    @classmethod
    def _test(cls, test_filename):
        # Return thunk to test for js file,
        # This is to 'trick' unittest so as to generate these dynamically.
        return lambda self: self.generate(test_filename)

    def generate(self, test_filename):
        test_abs = os.path.join(tests_path, test_filename)
        test = read_test(test_abs)
        exit_code = int(test.get("exit_code", 0))
        args = test.get("args", "").split(" ")
        check_stderr = str2bool(test.get("check_stderr", "false"))
        stderr = subprocess.STDOUT if check_stderr else open(os.devnull, 'w')
        stdin_input = (test.get("input",
                                "").strip().decode("string_escape").replace(
                                    "\r\n", "\n"))
        has_stdin_input = len(stdin_input) > 0

        output_abs = os.path.join(root_path, test.get("output", ""))
        with open(output_abs, 'r') as f:
            expected_out = f.read()
        cmd = [self.deno_exe] + args
        actual_code = 0
        try:
            if has_stdin_input:
                # Provided stdin
                proc = subprocess.Popen(
                    cmd,
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    stderr=stderr)
                actual_out, _ = proc.communicate(stdin_input)
                actual_out = actual_out.replace("\r\n", "\n")
            else:
                # No stdin sent
                actual_out = subprocess.check_output(
                    cmd, universal_newlines=True, stderr=stderr)

        except subprocess.CalledProcessError as e:
            actual_code = e.returncode
            actual_out = e.output

        self.assertEqual(exit_code, actual_code)

        actual_out = strip_ansi_codes(actual_out)
        if not pattern_match(expected_out, actual_out):
            # This will always throw since pattern_match failed.
            self.assertEqual(expected_out, actual_out)


# Add a methods for each test file in tests_path.
for fn in sorted(
        filename for filename in os.listdir(tests_path)
        if filename.endswith(".test")):

    t = TestIntegrations._test(fn)
    tn = t.__name__ = "test_" + fn.split(".")[0]
    setattr(TestIntegrations, tn, t)

if __name__ == "__main__":
    with http_server.spawn():
        run_tests()