def test_trumped_by(self): compile_rule.register_compile('TRUMPED_BY', 'genfiles/{{path}}.dot.js', ['??'], self.copy_compile, trumped_by=['DOUBLE-BRACE']) cr = compile_rule.find_compile_rule('genfiles/path/foo.dot.js') self.assertEqual('DOUBLE-BRACE', cr.label)
def test_cannot_glob_over_generated_files(self): with self.assertRaises(AssertionError): compile_rule.register_compile( 'GENFILES GLOB', 'genfiles/genfiles_glob', ['genfiles/*'], CopyCompile())
def test_outfile_must_live_in_genfiles(self): with self.assertRaises(AssertionError): compile_rule.register_compile( 'NOT GENFILES GLOB', 'not_genfiles/genfiles_glob', ['genfiles/*'], CopyCompile())
def test_missing_input_file_computed_input(self): class ComputedInput(computed_inputs.ComputedInputsBase): def input_patterns(self, outfile_name, context, triggers, changed): return ['genfiles/i_number_2'] # By having genfiles/bnumber be a trigger-file to compute the # inputs to bnumber.rev, we force bnumber to be immediate-built. # This should also cause us to build its non-input dep, i_letter_a. compile_rule.register_compile( 'MISSING FILES: IMMEDIATE', 'genfiles/i_number_2.rev', ComputedInput(['genfiles/bletter']), self.rev_compile) os.unlink(self._abspath('a1')) with mock.patch('kake.log.exception') as logger: with self.assertRaises(IOError): _build('genfiles/i_number_2.rev') self.assertEqual( [mock.call('FATAL ERROR building %s (needed via %s)', 'genfiles/i_letter_a', ('genfiles/i_number_2.rev (via computed dep)' ' -> genfiles/bletter' ' -> genfiles/fletter' ' -> genfiles/i_letter_a'))], logger.call_args_list)
def test_input_globs(self): # This will match a1, a2, b1, b2 compile_rule.register_compile('BOTH GLOB', 'genfiles/both_glob', ['??'], self.copy_compile) cr = compile_rule.find_compile_rule('genfiles/both_glob') self.assertEqual(['a1', 'a2', 'b1', 'b2'], cr.input_files('genfiles/both_glob'))
def test_labels_must_be_unique(self): compile_rule.register_compile('NON-UNIQUE LABEL', 'genfiles/{{path}}_copy_2', ['{{path}}2'], self.copy_compile) with self.assertRaises(AssertionError): compile_rule.register_compile('NON-UNIQUE LABEL', 'genfiles/subdir/{{path}}_copy_2', ['genfiles/subdir/{{path}}2'], self.rev_compile)
def test_sneaky_underscore(self): compile_rule.register_compile( 'UNDERSCORE VIA VAR', 'genfiles/{{path}}', ['{{path}}'], CopyCompile()) with self.assertRaises(AssertionError): kake.make.build('genfiles/_bad_underscore')
def test_we_die_if_buildmany_fails_but_not_during_binary_search(self): compile_rule.register_compile( 'FAIL', 'genfiles/fail*', ['a1'], FailToBuild()) with self.assertRaises(Exception): _build_many([('genfiles/fail1', {}), ('genfiles/fail2', {}), ('genfiles/fail3', {}), ('genfiles/fail4', {})])
def test_compute_crc(self): compile_rule.register_compile('COMPUTE CRC', 'genfiles/has_crc', ['??'], self.copy_compile, compute_crc=True) cr = compile_rule.find_compile_rule('genfiles/has_crc') self.assertTrue(cr.compute_crc) cr = compile_rule.find_compile_rule('genfiles/both_a_1') self.assertFalse(cr.compute_crc)
def test_var_with_underscore(self): # Testing {var_with_underscore} compile_rule.register_compile('VAR WITH UNDERSCORE', 'genfiles/us/{var_with_underscore}.js', ['{var_with_underscore}2'], self.rev_compile) cr = compile_rule.find_compile_rule('genfiles/us/foo.js') self.assertNotEqual(None, cr) self.assertEqual({'{var_with_underscore}': 'foo'}, cr.var_values('genfiles/us/foo.js'))
def test_circular_dep(self): # testing circular deps compile_rule.register_compile('CIRCULAR 1', 'genfiles/circular1', ['genfiles/circular2'], self.copy_compile) compile_rule.register_compile('CIRCULAR 2', 'genfiles/circular2', ['genfiles/circular1'], self.copy_compile) graph = build.DependencyGraph() with self.assertRaises(build.CompileFailure): self._add_to_dependency_graph('genfiles/circular1', graph)
def test_must_not_start_with_underscore(self): compile_rule.register_compile( 'UNDERSCORE IN GENFILES SUBDIR', 'genfiles/dir/_underscore_ok_here', ['foo/infile'], CopyCompile()) with self.assertRaises(AssertionError): compile_rule.register_compile( 'UNDERSCORE IN GENFILES MAINDIR', 'genfiles/_underscore_not_ok_here', ['foo/infile'], CopyCompile())
def test_must_be_in_genfiles(self): compile_rule.register_compile( 'OUTFILE IN GENFILES', 'genfiles/outfile', ['foo/infile'], CopyCompile()) with self.assertRaises(AssertionError): compile_rule.register_compile( 'OUTFILE NOT IN GENFILES', 'foo/outfile', ['foo/infile'], CopyCompile())
def test_force_recomputes_inputs(self): input_filenames = ['genfiles/i_number_2'] class ComputedInput(computed_inputs.ComputedInputsBase): def __init__(self, *args): super(ComputedInput, self).__init__(*args) def version(self): return 1 def input_patterns(self, outfile_name, context, triggers, changed): return input_filenames computed_input = ComputedInput(['a1']) compile_rule.register_compile( 'IMMEDIATE', 'genfiles/i_number_2.rev', computed_input, self.copy_compile) # We should be calling build twice, once for i_number_2.rev and once # for the input 'genfiles/i_number_2' with self.assertCalled(self.copy_compile._build, 2): _build('genfiles/i_number_2.rev') self.assertFileDoesNotExist('genfiles/i_number_1') self.assertFile('genfiles/i_number_2', 'a2: line 1\na2: line 2\nb2: line 1\nb2: line 2\n') # Now lets change the computed input file names input_filenames = ['genfiles/i_number_2', 'genfiles/i_number_1'] # Rebuilding should not call _build at all because the previous inputs # and the trigger have not changed. with self.assertCalled(self.copy_compile._build, 0): _build('genfiles/i_number_2.rev') self.assertFileDoesNotExist('genfiles/i_number_1') self.assertFile('genfiles/i_number_2', 'a2: line 1\na2: line 2\nb2: line 1\nb2: line 2\n') # With the force flag though we should be recalculating the inputs and # build them both and i_number_2.rev with self.assertCalled(self.copy_compile._build, 3): _build('genfiles/i_number_2.rev', force=True) self.assertFile('genfiles/i_number_1', 'a1: line 1\na1: line 2\nb1: line 1\nb1: line 2\n') self.assertFile('genfiles/i_number_2', 'a2: line 1\na2: line 2\nb2: line 1\nb2: line 2\n')
def test_find_compile_rule_prefers_more_directory_parts(self): # Something that uses two vs three directory parts compile_rule.register_compile('TWO DIRS', 'genfiles/{{path}}_copy_2', ['{{path}}2'], self.copy_compile) compile_rule.register_compile('THREE DIRS', 'genfiles/subdir/{{path}}_copy_2', ['genfiles/subdir/{{path}}2'], self.rev_compile) cr = compile_rule.find_compile_rule('genfiles/make_a_copy_2') self.assertEqual('genfiles/{{path}}_copy_2', cr.output_pattern) cr = compile_rule.find_compile_rule('genfiles/whatever/make_a_copy_2') self.assertEqual('genfiles/{{path}}_copy_2', cr.output_pattern) cr = compile_rule.find_compile_rule('genfiles/subdir/make_a_copy_2') self.assertEqual('genfiles/subdir/{{path}}_copy_2', cr.output_pattern)
def test_input_map(self): # Something that uses a 'system var' in the context. compile_rule.register_compile('INPUT MAP', 'genfiles/input_map', [], WriteContextInputMap()) _build_many([('genfiles/input_map', {}), ('genfiles/fletter', {})]) with open(os.path.join(self.tmpdir, 'genfiles', 'input_map')) as f: input_map = json.load(f) expected = { 'genfiles/fletter': ['genfiles/i_letter_a', 'genfiles/i_letter_b'], 'genfiles/i_letter_a': ['a1', 'a2'], 'genfiles/i_letter_b': ['b1', 'b2'], 'genfiles/input_map': [] } self.assertEqual(expected, input_map)
def test_maybe_symlink_to(self): compile_rule.register_compile('SYMLINK', 'genfiles/bletter_symlink', ['genfiles/fletter'], self.rev_compile, maybe_symlink_to='genfiles/bletter') _build('genfiles/bletter_symlink') self.assertTrue( os.path.islink(self._abspath('genfiles', 'bletter_symlink'))) self.assertEqual( os.path.join('bletter'), os.readlink(self._abspath('genfiles', 'bletter_symlink'))) # Check that when we rebuild, it doesn't try to symlink again. with self.assertCalled(os.symlink, 0): _build('genfiles/bletter_symlink')
def test_immediate_build(self): class ComputedInput(computed_inputs.ComputedInputsBase): def __init__(self, test_method, *args): super(ComputedInput, self).__init__(*args) self.test_method = test_method def version(self): return 1 def input_patterns(self, outfile_name, context, triggers, changed): # Not only should our trigger have been built, so should # its non-input deps. self.test_method.assertFile('genfiles/i_letter_a', ('a1: line 1\na1: line 2\n' 'a2: line 1\na2: line 2\n')) return ['genfiles/i_number_2'] # By having genfiles/bnumber be a trigger-file to compute the # inputs to bnumber.rev, we force bnumber to be immediate-built. # This should also cause us to build its non-input dep, i_letter_a. compile_rule.register_compile( 'IMMEDIATE', 'genfiles/i_number_2.rev', ComputedInput(self, ['genfiles/bnumber']), self.rev_compile) _build('genfiles/i_number_2.rev') # This should also have built i_number_2, which is what the # ComputedInput returns. self.assertFile('genfiles/i_number_2', 'a2: line 1\na2: line 2\nb2: line 1\nb2: line 2\n') # Make sure that immediate builds can also raise an exception when # these is no matching rule compile_rule.register_compile( 'IMMEDIATE2', 'genfiles/not_a_real_file.bmp', ComputedInput( self, ['genfiles/not_real_either']), self.rev_compile) with self.assertRaises( compile_rule.NoBuildRuleCompileFailure): _build('genfiles/not_a_real_file.bmp')
def test_find_compile_rule_prefers_longer_extensions(self): # Something that uses one vs two vs three extensions compile_rule.register_compile( 'ONE DOT', 'genfiles/subdir/{{path}}.2', ['{{path}}2'], self.copy_compile) compile_rule.register_compile( 'TWO DOTS', 'genfiles/{{path}}.copy.2', ['{{path}}2'], self.rev_compile) compile_rule.register_compile( 'TWO DOTS NO VARS', 'genfiles/most_specific.copy.2', ['most_specific2'], self.rev_compile) cr = compile_rule.find_compile_rule( 'genfiles/subdir/make_a.copy.2') self.assertEqual('genfiles/{{path}}.copy.2', cr.output_pattern) cr = compile_rule.find_compile_rule( 'genfiles/subdir/make_a.dupe.2') self.assertEqual('genfiles/subdir/{{path}}.2', cr.output_pattern) cr = compile_rule.find_compile_rule( 'genfiles/most_specific.copy.2') self.assertEqual('genfiles/most_specific.copy.2', cr.output_pattern)
def setUp(self): super(TestBase, self).setUp() # sets up self.tmpdir as ka-root os.makedirs(os.path.join(self.tmpdir, 'genfiles', 'computed_inputs')) for filename in ('a1', 'a2', 'b1', 'b2', 'number3'): with open(self._abspath(filename), 'w') as f: f.write('%s: line 1' % filename + "\n") f.write('%s: line 2' % filename + "\n") compile_rule.register_compile('STATIC', 'genfiles/computed_inputs/static', ComputedStaticInputs(['a1', 'a2']), CopyCompile()) compile_rule.register_compile('UNNORMALIZED', 'genfiles/computed_inputs/unnormalized', UnnormalizedComputedInputs(['a1', 'a2']), CopyCompile()) compile_rule.register_compile('A', 'genfiles/computed_inputs/a{number}', ComputedInputsFromVar(['number3']), CopyCompile()) compile_rule.register_compile( 'B', 'genfiles/computed_inputs/b{number}', ComputedInputsFromVar(['b{number}'], compute_crc=True), CopyCompile()) compile_rule.register_compile( 'B TAKE 2', 'genfiles/computed_2/b{number}', ComputedInputsFromVar(['genfiles/computed_inputs/b{number}']), CopyCompile()) compile_rule.register_compile( 'FROM CONTEXT', 'genfiles/computed_fromcontext/index', ComputedInputsFromContext(['genfiles/computed_inputs/b1']), CopyCompile()) compile_rule.register_compile( 'COMPUTED', 'genfiles/computed_inputs/content', ComputedInputsFromFileContents(['a1'], compute_crc=True), CopyCompile()) compile_rule.register_compile( 'CURR', 'genfiles/computed_inputs/curr', ComputedStaticInputs([computed_inputs.CURRENT_INPUTS]), CopyCompile()) compile_rule.register_compile( 'CURR2', 'genfiles/computed_inputs/curr2', ComputedInputsFromChangedContents( ['a1', computed_inputs.CURRENT_INPUTS]), CopyCompile()) compile_rule.register_compile( 'FORCE', 'genfiles/computed_inputs/force', ComputedStaticInputs(computed_inputs.FORCE), CopyCompile())
def setUp(self): super(TestComputedIncludes, self).setUp() os.makedirs(self._abspath('includes')) with open(self._abspath('a.c'), 'w') as f: f.write('#include <stdio.h>' + "\n") f.write('#include "a.h"' + "\n") f.write('int main() { return 0; }' + "\n") with open(self._abspath('commented.c'), 'w') as f: f.write('/*' + "\n") f.write('#include "a.h"' + "\n") f.write('*/' + "\n") f.write('#include "includes/d.h"' + "\n") with open(self._abspath('a.h'), 'w') as f: f.write('#include "includes/b.h"' + "\n") with open(self._abspath('stdio.h'), 'w') as f: f.write('' + "\n") with open(self._abspath(os.path.join('includes', 'b.h')), 'w') as f: f.write('#include "c.h"' + "\n") with open(self._abspath(os.path.join('includes', 'c.h')), 'w') as f: f.write('#define AVOID_CIRCULAR_INCLUDE 1' + "\n") f.write('#include "b.h"' + "\n") f.write('#include "../a.h"' + "\n") with open(self._abspath(os.path.join('includes', 'd.h')), 'w') as f: f.write('#define MY_USE "hello, world"' + "\n") with open(self._abspath('b.c'), 'w') as f: f.write('#include "includes/b.h"' + "\n") with open(self._abspath('double_include.c'), 'w') as f: f.write('#include "./a.h"' + "\n") f.write('#include "./a.h"' + "\n") with open(self._abspath('yelling.loudc'), 'w') as f: f.write('#INCLUDE "VUVUZELA.C"' + "\n") f.write('#INCLUDE "GODZILLA.C"' + "\n") f.write('INT MAIN() { RETURN 0; }' + "\n") with open(self._abspath('vuvuzela.loudc'), 'w') as f: f.write('#INCLUDE "GODZILLA.C"' + "\n") with open(self._abspath('godzilla.loudc'), 'w') as f: f.write('#INCLUDE "VUVUZELA.C"' + "\n") f.write('#DEFINE LOCALE "ja-JP"' + "\n") with open(self._abspath('magic.c'), 'w') as f: f.write('#include "?.h"' + "\n") self.includer = computed_inputs.ComputedIncludeInputs( '{{path}}.c', r'^#include\s+"(.*?)"', other_inputs=['a1']) compile_rule.register_compile('II', 'genfiles/{{path}}.ii', self.includer, CopyCompile()) self.full_includer = (computed_inputs.ComputedIncludeInputs( '{{path}}.c', r'^#include\s+"(.*?)"|^#include\s+<(.*?)>')) compile_rule.register_compile('FULLII', 'genfiles/{{path}}.fullii', self.full_includer, CopyCompile()) self.genfiles_includer = ComputedIncludeInputsSubclass( 'genfiles/{{path}}.c', r'^#include\s+"(.*?)"') compile_rule.register_compile('GENII', 'genfiles/{{path}}.genii', self.genfiles_includer, CopyCompile()) self.var_dep_includer = VarDependentComputedIncludeInputs( 'magic.c', r'^#include\s+"(.*?)"') compile_rule.register_compile('VARII', 'genfiles/{{path}}.varii', self.var_dep_includer, CopyCompile()) self.no_comment_dep_includer = NoCommentComputedIncludeInputs( '{{path}}.c', r'^#include\s+"(.*?)"') compile_rule.register_compile('NCII', 'genfiles/{{path}}.ncii', self.no_comment_dep_includer, CopyCompile()) compile_rule.register_compile('C', 'genfiles/{{path}}.c', ['{{path}}.loudc'], DowncaseCompile())
def setUp(self): super(TestBase, self).setUp() # sets up self.tmpdir as ka-root for filename in ('a1', 'a2', 'b1', 'b2', 'number3'): with open(self._abspath(filename), 'w') as f: f.write('%s: line 1' % filename + "\n") f.write('%s: line 2' % filename + "\n") self.copy_compile = CopyCompile() self.rev_compile = RevCompile() self.write_context = WriteContext() # i_number_1 depends on a1 and b1, likewise i_number_2. compile_rule.register_compile( 'NUMBER', 'genfiles/i_number_{number}', ['a{number}', 'b{number}'], self.copy_compile) # i_letter_a depends on a1 and a2, likewise i_letter_b. compile_rule.register_compile( 'LETTER', 'genfiles/i_letter_{letter}', ['{letter}1', '{letter}2'], self.copy_compile) # fnumber depends on i_number_1 and i_number_2 compile_rule.register_compile( 'FNUMBER', 'genfiles/fnumber', ['genfiles/i_number_1', 'genfiles/i_number_2'], self.copy_compile) # fletter depends on i_letter_a and i_letter_b compile_rule.register_compile( 'FLETTER', 'genfiles/fletter', ['genfiles/i_letter_a', 'genfiles/i_letter_b'], self.copy_compile) # It uses a different instance of CopyCompile() in order to test # that case in TestDependencyChunking. compile_rule.register_compile( 'FMOST', 'genfiles/fmost', ['genfiles/i_letter_a', 'b1'], CopyCompile()) # bnumber depends on oletter, bletter depends on onumber compile_rule.register_compile( 'BLETTER', 'genfiles/bletter', ['genfiles/fletter'], self.rev_compile) compile_rule.register_compile( 'BNUMBER', 'genfiles/bnumber', ['genfiles/fnumber'], self.rev_compile, non_input_deps=['genfiles/i_letter_a']) # For testing the num-variables code, and crazy maybe_symlink_to. compile_rule.register_compile( 'I3', 'genfiles/i_number_3', ['number3'], self.rev_compile, maybe_symlink_to='genfiles/bletter') # Something that uses two variables compile_rule.register_compile( 'BOTH', 'genfiles/both_{letter}_{number}', ['{letter}{number}'], CopyWithVarCompile(), maybe_symlink_to='{letter}{number}') # Something that uses a user's context compile_rule.register_compile( 'CONTEXT', 'genfiles/context_content_{number}', [], self.write_context) # Testing {var} vs {{var}} compile_rule.register_compile( 'DOUBLE-BRACE', 'genfiles/path/{{path}}.js', ['{{path}}2'], self.rev_compile) compile_rule.register_compile( 'SINGLE-BRACE', 'genfiles/dir/{path}.js', ['{path}2'], self.rev_compile) # Testing building a lot of files at the same level. # We want to test build_many() and split_files() compile_rule.register_compile( 'BASED_ON_FILENAME (MANY)', 'genfiles/filename_content.m.{content}', [], WriteBasedOnFilenameMany()) compile_rule.register_compile( 'BASED_ON_FILENAME (SPLIT_OUTPUTS)', 'genfiles/filename_content.s.{content}', [], WriteBasedOnFilenameSplit()) compile_rule.register_compile( '200 FILES (BUILD_MANY)', 'genfiles/200files.build_many', ['genfiles/filename_content.m.%d' % i for i in range(200)], self.copy_compile) compile_rule.register_compile( '200 FILES (SPLIT_OUTPUTS)', 'genfiles/200files.split_outputs', ['genfiles/filename_content.s.%d' % i for i in range(200)], self.copy_compile)