Exemplo n.º 1
0
 def test_nomatch(self):
     aliases = PathAliases()
     aliases.add('/home/*/src', './mysrc')
     self.assert_unchanged(aliases, '/home/foo/a.py')
Exemplo n.º 2
0
    def update(self, other_data, aliases=None):
        """Update this data with data from several other `CoverageData` instances.

        If `aliases` is provided, it's a `PathAliases` object that is used to
        re-map paths to match the local machine's.
        """
        if self._has_lines and other_data._has_arcs:
            raise CoverageException("Can't combine arc data with line data")
        if self._has_arcs and other_data._has_lines:
            raise CoverageException("Can't combine line data with arc data")

        aliases = aliases or PathAliases()

        # Force the database we're writing to to exist before we start nesting
        # contexts.
        self._start_using()

        # Collector for all arcs, lines and tracers
        other_data.read()
        with other_data._connect() as conn:
            # Get files data.
            cur = conn.execute('select path from file')
            files = {path: aliases.map(path) for (path, ) in cur}
            cur.close()

            # Get contexts data.
            cur = conn.execute('select context from context')
            contexts = [context for (context, ) in cur]
            cur.close()

            # Get arc data.
            cur = conn.execute(
                'select file.path, context.context, arc.fromno, arc.tono '
                'from arc '
                'inner join file on file.id = arc.file_id '
                'inner join context on context.id = arc.context_id')
            arcs = [(files[path], context, fromno, tono)
                    for (path, context, fromno, tono) in cur]
            cur.close()

            # Get line data.
            cur = conn.execute(
                'select file.path, context.context, line_bits.numbits '
                'from line_bits '
                'inner join file on file.id = line_bits.file_id '
                'inner join context on context.id = line_bits.context_id')
            lines = {(files[path], context): numbits
                     for (path, context, numbits) in cur}
            cur.close()

            # Get tracer data.
            cur = conn.execute('select file.path, tracer '
                               'from tracer '
                               'inner join file on file.id = tracer.file_id')
            tracers = {files[path]: tracer for (path, tracer) in cur}
            cur.close()

        with self._connect() as conn:
            conn.isolation_level = 'IMMEDIATE'

            # Get all tracers in the DB. Files not in the tracers are assumed
            # to have an empty string tracer. Since Sqlite does not support
            # full outer joins, we have to make two queries to fill the
            # dictionary.
            this_tracers = {
                path: ''
                for path, in conn.execute('select path from file')
            }
            this_tracers.update({
                aliases.map(path): tracer
                for path, tracer in conn.execute(
                    'select file.path, tracer from tracer '
                    'inner join file on file.id = tracer.file_id')
            })

            # Create all file and context rows in the DB.
            conn.executemany('insert or ignore into file (path) values (?)',
                             ((file, ) for file in files.values()))
            file_ids = {
                path: id
                for id, path in conn.execute('select id, path from file')
            }
            conn.executemany(
                'insert or ignore into context (context) values (?)',
                ((context, ) for context in contexts))
            context_ids = {
                context: id
                for id, context in conn.execute(
                    'select id, context from context')
            }

            # Prepare tracers and fail, if a conflict is found.
            # tracer_paths is used to ensure consistency over the tracer data
            # and tracer_map tracks the tracers to be inserted.
            tracer_map = {}
            for path in files.values():
                this_tracer = this_tracers.get(path)
                other_tracer = tracers.get(path, '')
                # If there is no tracer, there is always the None tracer.
                if this_tracer is not None and this_tracer != other_tracer:
                    raise CoverageException(
                        "Conflicting file tracer name for '%s': %r vs %r" %
                        (path, this_tracer, other_tracer))
                tracer_map[path] = other_tracer

            # Prepare arc and line rows to be inserted by converting the file
            # and context strings with integer ids. Then use the efficient
            # `executemany()` to insert all rows at once.
            arc_rows = ((file_ids[file], context_ids[context], fromno, tono)
                        for file, context, fromno, tono in arcs)

            # Get line data.
            cur = conn.execute(
                'select file.path, context.context, line_bits.numbits '
                'from line_bits '
                'inner join file on file.id = line_bits.file_id '
                'inner join context on context.id = line_bits.context_id')
            for path, context, numbits in cur:
                key = (aliases.map(path), context)
                if key in lines:
                    numbits = numbits_union(lines[key], numbits)
                lines[key] = numbits
            cur.close()

            self._choose_lines_or_arcs(arcs=bool(arcs), lines=bool(lines))

            # Write the combined data.
            conn.executemany(
                'insert or ignore into arc '
                '(file_id, context_id, fromno, tono) values (?, ?, ?, ?)',
                arc_rows)
            conn.execute("delete from line_bits")
            conn.executemany(
                "insert into line_bits "
                "(file_id, context_id, numbits) values (?, ?, ?)",
                [(file_ids[file], context_ids[context], numbits)
                 for (file, context), numbits in lines.items()])
            conn.executemany(
                'insert or ignore into tracer (file_id, tracer) values (?, ?)',
                ((file_ids[filename], tracer)
                 for filename, tracer in tracer_map.items()))

        # Update all internal cache data.
        self._reset()
        self.read()
Exemplo n.º 3
0
 def test_noop(self):
     aliases = PathAliases()
     self.assert_unchanged(aliases, '/ned/home/a.py')
Exemplo n.º 4
0
 def test_windows_root_paths(self):
     aliases = PathAliases()
     aliases.add('X:\\', '/tmp/src')
     self.assert_mapped(aliases, "X:\\a\\file.py", "/tmp/src/a/file.py")
     self.assert_mapped(aliases, "X:\\file.py", "/tmp/src/file.py")
Exemplo n.º 5
0
 def test_leading_wildcard(self):
     aliases = PathAliases()
     aliases.add('*/d1', './mysrc1')
     aliases.add('*/d2', './mysrc2')
     self.assert_mapped(aliases, '/foo/bar/d1/x.py', './mysrc1/x.py')
     self.assert_mapped(aliases, '/foo/bar/d2/y.py', './mysrc2/y.py')
Exemplo n.º 6
0
 def test_no_accidental_munging(self):
     aliases = PathAliases()
     aliases.add(r'c:\Zoo\boo', 'src/')
     aliases.add('/home/ned$', 'src/')
     self.assert_mapped(aliases, r'c:\Zoo\boo\foo.py', 'src/foo.py')
     self.assert_mapped(aliases, r'/home/ned$/foo.py', 'src/foo.py')
Exemplo n.º 7
0
 def test_multiple_wildcard(self):
     aliases = PathAliases()
     aliases.add('/home/jenkins/*/a/*/b/*/django', './django')
     self.assert_mapped(aliases,
                        '/home/jenkins/xx/a/yy/b/zz/django/foo/bar.py',
                        './django/foo/bar.py')
Exemplo n.º 8
0
 def test_no_accidental_match(self):
     aliases = PathAliases()
     aliases.add('/home/*/src', './mysrc')
     self.assert_unchanged(aliases, '/home/foo/srcetc')
Exemplo n.º 9
0
 def test_multiple_patterns(self):
     aliases = PathAliases()
     aliases.add('/home/*/src', './mysrc')
     aliases.add('/lib/*/libsrc', './mylib')
     self.assert_mapped(aliases, '/home/foo/src/a.py', './mysrc/a.py')
     self.assert_mapped(aliases, '/lib/foo/libsrc/a.py', './mylib/a.py')
Exemplo n.º 10
0
    def update(self, other_data, aliases=None):
        if self._has_lines and other_data._has_arcs:
            raise CoverageException("Can't combine arc data with line data")
        if self._has_arcs and other_data._has_lines:
            raise CoverageException("Can't combine line data with arc data")

        aliases = aliases or PathAliases()

        # See what we had already measured, for accurate conflict reporting.
        this_measured = self.measured_files()

        other_files = set()

        # Force the database we're writing to to exist before we start nesting
        # contexts.
        self._start_using()

        # Start a single transaction in each file.
        with self._connect(), other_data._connect():
            # lines
            if other_data._has_lines:
                for context in other_data.measured_contexts():
                    self.set_context(context)
                    for filename in other_data.measured_files():
                        lines = set(other_data.lines(filename,
                                                     context=context))
                        if lines:
                            other_files.add(filename)
                            filename = aliases.map(filename)
                            lines.update(
                                self.lines(filename, context=context) or ())
                            self.add_lines({filename: lines})

            # arcs
            if other_data._has_arcs:
                for context in other_data.measured_contexts():
                    self.set_context(context)
                    for filename in other_data.measured_files():
                        arcs = set(other_data.arcs(filename, context=context))
                        if arcs:
                            other_files.add(filename)
                            filename = aliases.map(filename)
                            arcs.update(
                                self.arcs(filename, context=context) or ())
                            self.add_arcs({filename: arcs})

            # file_tracers
            for filename in other_files:
                other_plugin = other_data.file_tracer(filename)
                filename = aliases.map(filename)
                if filename in this_measured:
                    this_plugin = self.file_tracer(filename)
                else:
                    this_plugin = None
                if this_plugin is None:
                    self.add_file_tracers({filename: other_plugin})
                elif this_plugin != other_plugin:
                    raise CoverageException(
                        "Conflicting file tracer name for '%s': %r vs %r" % (
                            filename,
                            this_plugin,
                            other_plugin,
                        ))
Exemplo n.º 11
0
 def test_no_accidental_match(self):
     aliases = PathAliases()
     aliases.add('/home/*/src', './mysrc')
     self.assertEqual(aliases.map('/home/foo/srcetc'), '/home/foo/srcetc')
Exemplo n.º 12
0
 def test_nomatch(self):
     aliases = PathAliases()
     aliases.add('/home/*/src', './mysrc')
     self.assertEqual(aliases.map('/home/foo/a.py'), '/home/foo/a.py')
Exemplo n.º 13
0
 def test_noop(self):
     aliases = PathAliases()
     self.assertEqual(aliases.map('/ned/home/a.py'), '/ned/home/a.py')
Exemplo n.º 14
0
 def test_noop(self):
     aliases = PathAliases()
     self.assert_not_mapped(aliases, '/ned/home/a.py')