3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 def _actionAppend(a1
, a2
):
44 for curr_a
in [a1
, a2
]:
45 if isinstance(curr_a
, MyAction
):
47 elif isinstance(curr_a
, MyListAction
):
48 all
.extend(curr_a
.list)
49 elif isinstance(curr_a
, list):
52 raise Exception('Cannot Combine Actions')
53 return MyListAction(all
)
56 def __add__(self
, other
):
57 return _actionAppend(self
, other
)
59 def __radd__(self
, other
):
60 return _actionAppend(other
, self
)
62 class MyAction(MyActionBase
):
63 def __init__(self
) -> None:
66 def __call__(self
, target
, source
, env
, executor
=None) -> int:
67 global built_it
, built_target
, built_source
, built_args
, built_order
69 target
= executor
.get_all_targets()
70 source
= executor
.get_all_sources()
75 built_order
= built_order
+ 1
76 self
.order
= built_order
79 def get_implicit_deps(self
, target
, source
, env
):
83 def __init__(self
, env
=None, targets
=[], sources
=[]) -> None:
85 self
.targets
= targets
86 self
.sources
= sources
87 def get_build_env(self
):
89 def get_build_scanner_path(self
, scanner
) -> str:
90 return 'executor would call %s' % scanner
91 def cleanup(self
) -> None:
93 def scan_targets(self
, scanner
) -> None:
96 d
= scanner(self
.targets
)
97 for t
in self
.targets
:
99 def scan_sources(self
, scanner
) -> None:
102 d
= scanner(self
.sources
)
103 for t
in self
.targets
:
106 class MyListAction(MyActionBase
):
107 def __init__(self
, list) -> None:
109 def __call__(self
, target
, source
, env
) -> None:
111 A(target
, source
, env
)
114 def __init__(self
, **kw
) -> None:
116 self
._dict
.update(kw
)
117 def __getitem__(self
, key
):
118 return self
._dict
[key
]
119 def get(self
, key
, default
= None):
120 return self
._dict
.get(key
, default
)
121 def Dictionary(self
, *args
):
123 def Override(self
, overrides
):
124 d
= self
._dict
.copy()
126 return Environment(**d
)
127 def _update(self
, dict) -> None:
128 self
._dict
.update(dict)
129 def get_factory(self
, factory
):
130 return factory
or MyNode
131 def get_scanner(self
, scanner_key
):
133 return self
._dict
['SCANNERS'][0]
140 def __init__(self
, env
=None, is_explicit
: bool=True) -> None:
141 if env
is None: env
= Environment()
144 self
.action
= MyAction()
145 self
.source_factory
= MyNode
146 self
.is_explicit
= is_explicit
147 self
.target_scanner
= None
148 self
.source_scanner
= None
149 def targets(self
, t
):
151 def get_actions(self
):
153 def get_contents(self
, target
, source
, env
) -> int:
156 class NoneBuilder(Builder
):
157 def execute(self
, target
, source
, env
):
158 Builder
.execute(self
, target
, source
, env
)
161 class ListBuilder(Builder
):
162 def __init__(self
, *nodes
) -> None:
165 def execute(self
, target
, source
, env
):
166 if hasattr(self
, 'status'):
170 target
= self
.nodes
[0]
171 self
.status
= Builder
.execute(self
, target
, source
, env
)
174 def execute(self
, target
, source
, env
) -> int:
178 def execute(self
, target
, source
, env
):
179 raise SCons
.Errors
.BuildError
181 class ExceptBuilder2
:
182 def execute(self
, target
, source
, env
):
183 raise Exception("foo")
187 def __call__(self
, node
):
189 return node
.GetTag('found_includes')
190 def path(self
, env
, dir=None, target
=None, source
=None, kw
={}):
192 def select(self
, node
):
194 def recurse_nodes(self
, nodes
):
197 class MyNode(SCons
.Node
.Node
):
198 """The base Node class contains a number of do-nothing methods that
199 we expect to be overridden by real, functional Node subclasses. So
200 simulate a real, functional Node subclass.
202 def __init__(self
, name
) -> None:
205 self
.Tag('found_includes', [])
206 def __str__(self
) -> str:
208 def get_found_includes(self
, env
, scanner
, target
):
212 def __init__(self
, val
) -> None:
215 def __init__(self
, val
) -> None:
217 def signature(self
, args
):
219 def collect(self
, args
):
228 class NodeInfoBaseTestCase(unittest
.TestCase
):
229 # The abstract class NodeInfoBase has not enough default slots to perform
230 # the merge and format test (arbitrary attributes do not work). Do it with a
231 # derived class that does provide the slots.
233 def test_merge(self
) -> None:
234 """Test merging NodeInfoBase attributes"""
236 class TestNodeInfo(SCons
.Node
.NodeInfoBase
):
237 __slots__
= ('a1', 'a2', 'a3')
249 assert ni1
.a1
== 1, ni1
.a1
250 assert ni1
.a2
== 222, ni1
.a2
251 assert ni1
.a3
== 333, ni1
.a3
253 def test_update(self
) -> None:
254 """Test the update() method"""
255 ni
= SCons
.Node
.NodeInfoBase()
256 ni
.update(SCons
.Node
.Node())
258 def test_format(self
) -> None:
259 """Test the NodeInfoBase.format() method"""
261 class TestNodeInfo(SCons
.Node
.NodeInfoBase
):
262 __slots__
= ('xxx', 'yyy', 'zzz')
270 assert f
== ['x', 'y', 'z'], f
272 field_list
= ['xxx', 'zzz', 'aaa']
274 f
= ni1
.format(field_list
)
275 assert f
== ['x', 'z', 'None'], f
279 class BuildInfoBaseTestCase(unittest
.TestCase
):
281 def test___init__(self
) -> None:
282 """Test BuildInfoBase initialization"""
283 n
= SCons
.Node
.Node()
284 bi
= SCons
.Node
.BuildInfoBase()
287 def test_merge(self
) -> None:
288 """Test merging BuildInfoBase attributes"""
289 n1
= SCons
.Node
.Node()
290 bi1
= SCons
.Node
.BuildInfoBase()
291 n2
= SCons
.Node
.Node()
292 bi2
= SCons
.Node
.BuildInfoBase()
301 assert bi1
.bsources
== 1, bi1
.bsources
302 assert bi1
.bdepends
== 222, bi1
.bdepends
303 assert bi1
.bact
== 333, bi1
.bact
306 class NodeTestCase(unittest
.TestCase
):
308 def test_build(self
) -> None:
309 """Test building a node
311 global built_it
, built_order
313 # Make sure it doesn't blow up if no builder is set.
316 assert built_it
is None
317 node
.build(extra_kw_argument
= 1)
318 assert built_it
is None
321 node
.builder_set(Builder())
322 node
.env_set(Environment())
324 node
.sources
= ["yyy", "zzz"]
327 assert built_target
== [node
], built_target
328 assert built_source
== ["yyy", "zzz"], built_source
332 node
.builder_set(NoneBuilder())
333 node
.env_set(Environment())
335 node
.sources
= ["rrr", "sss"]
336 node
.builder
.overrides
= { "foo" : 1, "bar" : 2 }
339 assert built_target
== [node
], built_target
340 assert built_source
== ["rrr", "sss"], built_source
341 assert built_args
["foo"] == 1, built_args
342 assert built_args
["bar"] == 2, built_args
346 lb
= ListBuilder(fff
, ggg
)
354 fff
.sources
= ["hhh", "iii"]
355 ggg
.sources
= ["hhh", "iii"]
359 assert built_target
== [fff
], built_target
360 assert built_source
== ["hhh", "iii"], built_source
364 assert built_target
== [ggg
], built_target
365 assert built_source
== ["hhh", "iii"], built_source
371 # NOTE: No env_set()! We should pull the environment from the builder.
372 b
.env
= Environment()
373 b
.overrides
= { "on" : 3, "off" : 4 }
377 assert built_target
[0] == jjj
, built_target
[0]
378 assert built_source
== [], built_source
379 assert built_args
["on"] == 3, built_args
380 assert built_args
["off"] == 4, built_args
382 def test_get_build_scanner_path(self
) -> None:
383 """Test the get_build_scanner_path() method"""
384 n
= SCons
.Node
.Node()
387 p
= n
.get_build_scanner_path('fake_scanner')
388 assert p
== "executor would call fake_scanner", p
390 def test_get_executor(self
) -> None:
391 """Test the get_executor() method"""
392 n
= SCons
.Node
.Node()
396 except AttributeError:
399 self
.fail("did not catch expected AttributeError")
406 n
= SCons
.Node
.Node()
407 n
.builder_set(Builder())
409 assert x
.env
== 'env1', x
.env
411 n
= SCons
.Node
.Node()
412 n
.builder_set(Builder())
415 assert x
.env
== 'env2', x
.env
417 def test_set_executor(self
) -> None:
418 """Test the set_executor() method"""
419 n
= SCons
.Node
.Node()
421 assert n
.executor
== 1, n
.executor
423 def test_executor_cleanup(self
) -> None:
424 """Test letting the executor cleanup its cache"""
425 n
= SCons
.Node
.Node()
431 def test_reset_executor(self
) -> None:
432 """Test the reset_executor() method"""
433 n
= SCons
.Node
.Node()
435 assert n
.executor
== 1, n
.executor
437 assert not hasattr(n
, 'executor'), "unexpected executor attribute"
439 def test_built(self
) -> None:
440 """Test the built() method"""
441 class SubNodeInfo(SCons
.Node
.NodeInfoBase
):
442 __slots__
= ('updated',)
443 def update(self
, node
) -> None:
445 class SubNode(SCons
.Node
.Node
):
446 def clear(self
) -> None:
450 n
.ninfo
= SubNodeInfo()
452 assert n
.cleared
, n
.cleared
453 assert n
.ninfo
.updated
, n
.ninfo
.cleared
455 def test_push_to_cache(self
) -> None:
456 """Test the base push_to_cache() method"""
457 n
= SCons
.Node
.Node()
458 r
= n
.push_to_cache()
461 def test_retrieve_from_cache(self
) -> None:
462 """Test the base retrieve_from_cache() method"""
463 n
= SCons
.Node
.Node()
464 r
= n
.retrieve_from_cache()
467 def test_visited(self
) -> None:
468 """Test the base visited() method
470 Just make sure it's there and we can call it.
472 n
= SCons
.Node
.Node()
475 def test_builder_set(self
) -> None:
476 """Test setting a Node's Builder
478 node
= SCons
.Node
.Node()
481 assert node
.builder
== b
483 def test_has_builder(self
) -> None:
484 """Test the has_builder() method
486 n1
= SCons
.Node
.Node()
487 assert n1
.has_builder() == 0
488 n1
.builder_set(Builder())
489 assert n1
.has_builder() == 1
491 def test_has_explicit_builder(self
) -> None:
492 """Test the has_explicit_builder() method
494 n1
= SCons
.Node
.Node()
495 assert not n1
.has_explicit_builder()
497 assert n1
.has_explicit_builder()
498 n1
.set_explicit(None)
499 assert not n1
.has_explicit_builder()
501 def test_get_builder(self
) -> None:
502 """Test the get_builder() method"""
503 n1
= SCons
.Node
.Node()
506 b
= n1
.get_builder(777)
511 b
= n1
.get_builder(999)
514 def test_multiple_side_effect_has_builder(self
) -> None:
515 """Test the multiple_side_effect_has_builder() method
517 n1
= SCons
.Node
.Node()
518 assert n1
.multiple_side_effect_has_builder() == 0
519 n1
.builder_set(Builder())
520 assert n1
.multiple_side_effect_has_builder() == 1
522 def test_is_derived(self
) -> None:
523 """Test the is_derived() method
525 n1
= SCons
.Node
.Node()
526 n2
= SCons
.Node
.Node()
527 n3
= SCons
.Node
.Node()
529 n2
.builder_set(Builder())
532 assert n1
.is_derived() == 0
533 assert n2
.is_derived() == 1
534 assert n3
.is_derived() == 1
536 def test_alter_targets(self
) -> None:
537 """Test the alter_targets() method
539 n
= SCons
.Node
.Node()
540 t
, m
= n
.alter_targets()
544 def test_is_up_to_date(self
) -> None:
545 """Test the default is_up_to_date() method."""
546 node
= SCons
.Node
.Node()
547 assert not node
.is_up_to_date()
549 def test_children_are_up_to_date(self
) -> None:
550 """Test the children_are_up_to_date() method used by subclasses
552 n1
= SCons
.Node
.Node()
553 n2
= SCons
.Node
.Node()
556 assert n1
.children_are_up_to_date(), "expected up to date"
557 n2
.set_state(SCons
.Node
.executed
)
558 assert not n1
.children_are_up_to_date(), "expected not up to date"
559 n2
.set_state(SCons
.Node
.up_to_date
)
560 assert n1
.children_are_up_to_date(), "expected up to date"
562 assert not n1
.children_are_up_to_date(), "expected not up to date"
564 def test_env_set(self
) -> None:
565 """Test setting a Node's Environment
567 node
= SCons
.Node
.Node()
572 def test_get_actions(self
) -> None:
573 """Test fetching a Node's action list
575 node
= SCons
.Node
.Node()
576 node
.builder_set(Builder())
577 a
= node
.builder
.get_actions()
578 assert isinstance(a
[0], MyAction
), a
[0]
580 def test_get_csig(self
) -> None:
581 """Test generic content signature calculation
584 class TestNodeInfo(SCons
.Node
.NodeInfoBase
):
585 __slots__
= ('csig',)
587 SCons
.Node
.Node
.NodeInfo
= TestNodeInfo
588 def my_contents(obj
) -> int:
590 SCons
.Node
._get
_contents
_map
[4] = my_contents
591 node
= SCons
.Node
.Node()
592 node
._func
_get
_contents
= 4
593 result
= node
.get_csig()
594 assert result
in ('550a141f12de6341fba65b0ad0433500', '9a3e61b6bcc8abec08f195526c3132d5a4a98cc0', '3538a1ef2e113da64249eea7bd068b585ec7ce5df73b2d1e319d8c9bf47eb314'), result
596 SCons
.Node
.Node
.NodeInfo
= SCons
.Node
.NodeInfoBase
598 def test_get_cachedir_csig(self
) -> None:
599 """Test content signature calculation for CacheDir
601 class TestNodeInfo(SCons
.Node
.NodeInfoBase
):
602 __slots__
= ('csig',)
604 SCons
.Node
.Node
.NodeInfo
= TestNodeInfo
605 def my_contents(obj
) -> int:
607 SCons
.Node
._get
_contents
_map
[4] = my_contents
608 node
= SCons
.Node
.Node()
609 node
._func
_get
_contents
= 4
610 result
= node
.get_cachedir_csig()
611 assert result
in ('15de21c670ae7c3f6f3f1f37029303c9', 'cfa1150f1787186742a9a884b73a43d8cf219f9b', '91a73fd806ab2c005c13b4dc19130a884e909dea3f72d46e30266fe1a1f588d8'), result
613 SCons
.Node
.Node
.NodeInfo
= SCons
.Node
.NodeInfoBase
615 def test_get_binfo(self
) -> None:
616 """Test fetching/creating a build information structure
618 class TestNodeInfo(SCons
.Node
.NodeInfoBase
):
619 __slots__
= ('csig',)
620 SCons
.Node
.Node
.NodeInfo
= TestNodeInfo
621 node
= SCons
.Node
.Node()
623 binfo
= node
.get_binfo()
624 assert isinstance(binfo
, SCons
.Node
.BuildInfoBase
), binfo
626 node
= SCons
.Node
.Node()
627 d
= SCons
.Node
.Node()
628 ninfo
= d
.get_ninfo()
629 assert isinstance(ninfo
, SCons
.Node
.NodeInfoBase
), ninfo
630 i
= SCons
.Node
.Node()
631 ninfo
= i
.get_ninfo()
632 assert isinstance(ninfo
, SCons
.Node
.NodeInfoBase
), ninfo
636 binfo
= node
.get_binfo()
637 assert isinstance(binfo
, SCons
.Node
.BuildInfoBase
), binfo
638 assert hasattr(binfo
, 'bsources')
639 assert hasattr(binfo
, 'bsourcesigs')
640 assert binfo
.bdepends
== [d
]
641 assert hasattr(binfo
, 'bdependsigs')
642 assert binfo
.bimplicit
== [i
]
643 assert hasattr(binfo
, 'bimplicitsigs')
645 def test_explain(self
) -> None:
646 """Test explaining why a Node must be rebuilt
648 class testNode(SCons
.Node
.Node
):
649 def __str__(self
) -> str: return 'xyzzy'
651 node
.exists
= lambda: None
652 # Can't do this with new-style classes (python bug #1066490)
653 #node.__str__ = lambda: 'xyzzy'
654 result
= node
.explain()
655 assert result
== "building `xyzzy' because it doesn't exist\n", result
657 class testNode2(SCons
.Node
.Node
):
658 def __str__(self
) -> str: return 'null_binfo'
663 node
.fs
.Top
= SCons
.Node
.Node()
664 result
= node
.explain()
665 assert result
is None, result
668 class Null_SConsignEntry
:
669 class Null_BuildInfo
:
670 def prepare_dependencies(self
) -> None:
672 binfo
= Null_BuildInfo()
673 return Null_SConsignEntry()
675 node
.get_stored_info
= get_null_info
676 #see above: node.__str__ = lambda: 'null_binfo'
677 result
= node
.explain()
678 assert result
== "Cannot explain why `null_binfo' is being rebuilt: No previous build information found\n", result
680 # XXX additional tests for the guts of the functionality some day
682 #def test_del_binfo(self):
683 # """Test deleting the build information from a Node
685 # node = SCons.Node.Node()
688 # assert not hasattr(node, 'binfo'), node
690 def test_store_info(self
) -> None:
691 """Test calling the method to store build information
693 node
= SCons
.Node
.Node()
694 SCons
.Node
.store_info_map
[node
.store_info
](node
)
696 def test_get_stored_info(self
) -> None:
697 """Test calling the method to fetch stored build information
699 node
= SCons
.Node
.Node()
700 result
= node
.get_stored_info()
701 assert result
is None, result
703 def test_set_always_build(self
) -> None:
704 """Test setting a Node's always_build value
706 node
= SCons
.Node
.Node()
707 node
.set_always_build()
708 assert node
.always_build
709 node
.set_always_build(3)
710 assert node
.always_build
== 3
712 def test_set_noclean(self
) -> None:
713 """Test setting a Node's noclean value
715 node
= SCons
.Node
.Node()
717 assert node
.noclean
== 1, node
.noclean
719 assert node
.noclean
== 1, node
.noclean
721 assert node
.noclean
== 0, node
.noclean
722 node
.set_noclean(None)
723 assert node
.noclean
== 0, node
.noclean
725 def test_set_precious(self
) -> None:
726 """Test setting a Node's precious value
728 node
= SCons
.Node
.Node()
732 assert node
.precious
== 7
734 def test_set_pseudo(self
) -> None:
735 """Test setting a Node's pseudo value
737 node
= SCons
.Node
.Node()
740 node
.set_pseudo(False)
741 assert not node
.pseudo
743 def test_exists(self
) -> None:
744 """Test evaluating whether a Node exists.
746 node
= SCons
.Node
.Node()
750 def test_exists_repo(self
) -> None:
751 """Test evaluating whether a Node exists locally or in a repository.
753 node
= SCons
.Node
.Node()
757 class MyNode(SCons
.Node
.Node
):
758 def exists(self
) -> str:
765 def test_prepare(self
) -> None:
766 """Test preparing a node to be built
768 By extension, this also tests the missing() method.
770 node
= SCons
.Node
.Node()
772 n1
= SCons
.Node
.Node()
773 n1
.builder_set(Builder())
775 node
.implicit_set
= set()
776 node
._add
_child
(node
.implicit
, node
.implicit_set
, [n1
])
778 node
.prepare() # should not throw an exception
780 n2
= SCons
.Node
.Node()
783 node
.implicit_set
= set()
784 node
._add
_child
(node
.implicit
, node
.implicit_set
, [n2
])
786 node
.prepare() # should not throw an exception
788 n3
= SCons
.Node
.Node()
790 node
.implicit_set
= set()
791 node
._add
_child
(node
.implicit
, node
.implicit_set
, [n3
])
793 node
.prepare() # should not throw an exception
795 class MyNode(SCons
.Node
.Node
):
800 node
.implicit_set
= set()
801 node
._add
_child
(node
.implicit
, node
.implicit_set
, [n4
])
805 except SCons
.Errors
.StopError
:
807 assert exc_caught
, "did not catch expected StopError"
809 def test_add_dependency(self
):
810 """Test adding dependencies to a Node's list.
812 node
= SCons
.Node
.Node()
813 assert node
.depends
== []
815 zero
= SCons
.Node
.Node()
817 one
= SCons
.Node
.Node()
818 two
= SCons
.Node
.Node()
819 three
= SCons
.Node
.Node()
820 four
= SCons
.Node
.Node()
821 five
= SCons
.Node
.Node()
822 six
= SCons
.Node
.Node()
824 node
.add_dependency([zero
])
825 assert node
.depends
== [zero
]
826 node
.add_dependency([one
])
827 assert node
.depends
== [zero
, one
]
828 node
.add_dependency([two
, three
])
829 assert node
.depends
== [zero
, one
, two
, three
]
830 node
.add_dependency([three
, four
, one
])
831 assert node
.depends
== [zero
, one
, two
, three
, four
]
834 node
.add_depends([[five
, six
]])
838 raise Exception("did not catch expected exception")
839 assert node
.depends
== [zero
, one
, two
, three
, four
]
842 def test_add_source(self
):
843 """Test adding sources to a Node's list.
845 node
= SCons
.Node
.Node()
846 assert node
.sources
== []
848 zero
= SCons
.Node
.Node()
849 one
= SCons
.Node
.Node()
850 two
= SCons
.Node
.Node()
851 three
= SCons
.Node
.Node()
852 four
= SCons
.Node
.Node()
853 five
= SCons
.Node
.Node()
854 six
= SCons
.Node
.Node()
856 node
.add_source([zero
])
857 assert node
.sources
== [zero
]
858 node
.add_source([one
])
859 assert node
.sources
== [zero
, one
]
860 node
.add_source([two
, three
])
861 assert node
.sources
== [zero
, one
, two
, three
]
862 node
.add_source([three
, four
, one
])
863 assert node
.sources
== [zero
, one
, two
, three
, four
]
866 node
.add_source([[five
, six
]])
870 raise Exception("did not catch expected exception")
871 assert node
.sources
== [zero
, one
, two
, three
, four
], node
.sources
873 def test_add_ignore(self
):
874 """Test adding files whose dependencies should be ignored.
876 node
= SCons
.Node
.Node()
877 assert node
.ignore
== []
879 zero
= SCons
.Node
.Node()
880 one
= SCons
.Node
.Node()
881 two
= SCons
.Node
.Node()
882 three
= SCons
.Node
.Node()
883 four
= SCons
.Node
.Node()
884 five
= SCons
.Node
.Node()
885 six
= SCons
.Node
.Node()
887 node
.add_ignore([zero
])
888 assert node
.ignore
== [zero
]
889 node
.add_ignore([one
])
890 assert node
.ignore
== [zero
, one
]
891 node
.add_ignore([two
, three
])
892 assert node
.ignore
== [zero
, one
, two
, three
]
893 node
.add_ignore([three
, four
, one
])
894 assert node
.ignore
== [zero
, one
, two
, three
, four
]
897 node
.add_ignore([[five
, six
]])
901 raise Exception("did not catch expected exception")
902 assert node
.ignore
== [zero
, one
, two
, three
, four
]
904 def test_get_found_includes(self
) -> None:
905 """Test the default get_found_includes() method
907 node
= SCons
.Node
.Node()
908 target
= SCons
.Node
.Node()
910 deps
= node
.get_found_includes(e
, None, target
)
911 assert deps
== [], deps
913 def test_get_implicit_deps(self
) -> None:
914 """Test get_implicit_deps()
917 target
= MyNode("ttt")
920 # No scanner at all returns []
921 deps
= node
.get_implicit_deps(env
, None, target
)
922 assert deps
== [], deps
927 node
.Tag('found_includes', [d1
, d2
])
929 # Simple return of the found includes
930 deps
= node
.get_implicit_deps(env
, s
, s
.path
)
931 assert deps
== [d1
, d2
], deps
933 # By default, our fake scanner recurses
937 d1
.Tag('found_includes', [e
, f
])
938 d2
.Tag('found_includes', [e
, f
])
939 f
.Tag('found_includes', [g
])
940 deps
= node
.get_implicit_deps(env
, s
, s
.path
)
941 assert deps
== [d1
, d2
, e
, f
, g
], list(map(str, deps
))
943 # Recursive scanning eliminates duplicates
944 e
.Tag('found_includes', [f
])
945 deps
= node
.get_implicit_deps(env
, s
, s
.path
)
946 assert deps
== [d1
, d2
, e
, f
, g
], list(map(str, deps
))
948 # Scanner method can select specific nodes to recurse
950 return [n
for n
in nodes
if str(n
)[0] != 'f']
951 s
.recurse_nodes
= no_fff
952 deps
= node
.get_implicit_deps(env
, s
, s
.path
)
953 assert deps
== [d1
, d2
, e
, f
], list(map(str, deps
))
955 # Scanner method can short-circuit recursing entirely
956 s
.recurse_nodes
= lambda nodes
: []
957 deps
= node
.get_implicit_deps(env
, s
, s
.path
)
958 assert deps
== [d1
, d2
], list(map(str, deps
))
960 def test_get_env_scanner(self
) -> None:
961 """Test fetching the environment scanner for a Node
963 node
= SCons
.Node
.Node()
965 env
= Environment(SCANNERS
= [scanner
])
966 s
= node
.get_env_scanner(env
)
967 assert s
== scanner
, s
968 s
= node
.get_env_scanner(env
, {'X':1})
969 assert s
== scanner
, s
971 def test_get_target_scanner(self
) -> None:
972 """Test fetching the target scanner for a Node
977 n
= SCons
.Node
.Node()
979 x
= n
.get_target_scanner()
982 def test_get_source_scanner(self
) -> None:
983 """Test fetching the source scanner for a Node
985 target
= SCons
.Node
.Node()
986 source
= SCons
.Node
.Node()
987 s
= target
.get_source_scanner(source
)
988 assert isinstance(s
, SCons
.Util
.Null
), s
994 class Builder1(Builder
):
995 def __call__(self
, source
):
996 r
= SCons
.Node
.Node()
999 class Builder2(Builder1
):
1000 def __init__(self
, scanner
) -> None:
1001 self
.source_scanner
= scanner
1003 builder
= Builder2(ts1
)
1005 targets
= builder([source
])
1006 s
= targets
[0].get_source_scanner(source
)
1009 target
.builder_set(Builder2(ts1
))
1010 target
.builder
.source_scanner
= ts2
1011 s
= target
.get_source_scanner(source
)
1014 builder
= Builder1(env
=Environment(SCANNERS
= [ts3
]))
1016 targets
= builder([source
])
1018 s
= targets
[0].get_source_scanner(source
)
1022 def test_scan(self
) -> None:
1023 """Test Scanner functionality
1026 node
= MyNode("nnn")
1027 node
.builder
= Builder()
1029 x
= MyExecutor(env
, [node
])
1033 node
.Tag('found_includes', [d
])
1035 node
.builder
.target_scanner
= s
1036 assert node
.implicit
is None
1040 assert node
.implicit
== [d
], node
.implicit
1042 # Check that scanning a node with some stored implicit
1043 # dependencies resets internal attributes appropriately
1044 # if the stored dependencies need recalculation.
1045 class StoredNode(MyNode
):
1046 def get_stored_implicit(self
):
1047 return [MyNode('implicit1'), MyNode('implicit2')]
1049 save_implicit_cache
= SCons
.Node
.implicit_cache
1050 save_implicit_deps_changed
= SCons
.Node
.implicit_deps_changed
1051 save_implicit_deps_unchanged
= SCons
.Node
.implicit_deps_unchanged
1052 SCons
.Node
.implicit_cache
= 1
1053 SCons
.Node
.implicit_deps_changed
= None
1054 SCons
.Node
.implicit_deps_unchanged
= None
1056 sn
= StoredNode("eee")
1057 sn
.builder_set(Builder())
1058 sn
.builder
.target_scanner
= s
1062 assert sn
.implicit
== [], sn
.implicit
1063 assert sn
.children() == [], sn
.children()
1066 SCons
.Node
.implicit_cache
= save_implicit_cache
1067 SCons
.Node
.implicit_deps_changed
= save_implicit_deps_changed
1068 SCons
.Node
.implicit_deps_unchanged
= save_implicit_deps_unchanged
1070 def test_scanner_key(self
) -> None:
1071 """Test that a scanner_key() method exists"""
1072 assert SCons
.Node
.Node().scanner_key() is None
1074 def test_children(self
) -> None:
1075 """Test fetching the non-ignored "children" of a Node.
1077 node
= SCons
.Node
.Node()
1078 n1
= SCons
.Node
.Node()
1079 n2
= SCons
.Node
.Node()
1080 n3
= SCons
.Node
.Node()
1081 n4
= SCons
.Node
.Node()
1082 n5
= SCons
.Node
.Node()
1083 n6
= SCons
.Node
.Node()
1084 n7
= SCons
.Node
.Node()
1085 n8
= SCons
.Node
.Node()
1086 n9
= SCons
.Node
.Node()
1087 n10
= SCons
.Node
.Node()
1088 n11
= SCons
.Node
.Node()
1089 n12
= SCons
.Node
.Node()
1091 node
.add_source([n1
, n2
, n3
])
1092 node
.add_dependency([n4
, n5
, n6
])
1094 node
.implicit_set
= set()
1095 node
._add
_child
(node
.implicit
, node
.implicit_set
, [n7
, n8
, n9
])
1096 node
._add
_child
(node
.implicit
, node
.implicit_set
, [n10
, n11
, n12
])
1097 node
.add_ignore([n2
, n5
, n8
, n11
])
1099 kids
= node
.children()
1100 for kid
in [n1
, n3
, n4
, n6
, n7
, n9
, n10
, n12
]:
1101 assert kid
in kids
, kid
1102 for kid
in [n2
, n5
, n8
, n11
]:
1103 assert kid
not in kids
, kid
1105 def test_all_children(self
) -> None:
1106 """Test fetching all the "children" of a Node.
1108 node
= SCons
.Node
.Node()
1109 n1
= SCons
.Node
.Node()
1110 n2
= SCons
.Node
.Node()
1111 n3
= SCons
.Node
.Node()
1112 n4
= SCons
.Node
.Node()
1113 n5
= SCons
.Node
.Node()
1114 n6
= SCons
.Node
.Node()
1115 n7
= SCons
.Node
.Node()
1116 n8
= SCons
.Node
.Node()
1117 n9
= SCons
.Node
.Node()
1118 n10
= SCons
.Node
.Node()
1119 n11
= SCons
.Node
.Node()
1120 n12
= SCons
.Node
.Node()
1122 node
.add_source([n1
, n2
, n3
])
1123 node
.add_dependency([n4
, n5
, n6
])
1125 node
.implicit_set
= set()
1126 node
._add
_child
(node
.implicit
, node
.implicit_set
, [n7
, n8
, n9
])
1127 node
._add
_child
(node
.implicit
, node
.implicit_set
, [n10
, n11
, n12
])
1128 node
.add_ignore([n2
, n5
, n8
, n11
])
1130 kids
= node
.all_children()
1131 for kid
in [n1
, n2
, n3
, n4
, n5
, n6
, n7
, n8
, n9
, n10
, n11
, n12
]:
1132 assert kid
in kids
, kid
1134 def test_state(self
) -> None:
1135 """Test setting and getting the state of a node
1137 node
= SCons
.Node
.Node()
1138 assert node
.get_state() == SCons
.Node
.no_state
1139 node
.set_state(SCons
.Node
.executing
)
1140 assert node
.get_state() == SCons
.Node
.executing
1141 assert SCons
.Node
.pending
< SCons
.Node
.executing
1142 assert SCons
.Node
.executing
< SCons
.Node
.up_to_date
1143 assert SCons
.Node
.up_to_date
< SCons
.Node
.executed
1144 assert SCons
.Node
.executed
< SCons
.Node
.failed
1146 def test_walker(self
) -> None:
1147 """Test walking a Node tree.
1152 nw
= SCons
.Node
.Walker(n1
)
1153 assert not nw
.is_done()
1154 assert nw
.get_next().name
== "n1"
1156 assert nw
.get_next() is None
1160 n1
.add_source([n2
, n3
])
1162 nw
= SCons
.Node
.Walker(n1
)
1164 assert n
.name
== "n2", n
.name
1166 assert n
.name
== "n3", n
.name
1168 assert n
.name
== "n1", n
.name
1176 n2
.add_source([n4
, n5
])
1177 n3
.add_dependency([n6
, n7
])
1179 nw
= SCons
.Node
.Walker(n1
)
1180 assert nw
.get_next().name
== "n4"
1181 assert nw
.get_next().name
== "n5"
1182 assert n2
in nw
.history
1183 assert nw
.get_next().name
== "n2"
1184 assert nw
.get_next().name
== "n6"
1185 assert nw
.get_next().name
== "n7"
1186 assert n3
in nw
.history
1187 assert nw
.get_next().name
== "n3"
1188 assert n1
in nw
.history
1189 assert nw
.get_next().name
== "n1"
1190 assert nw
.get_next() is None
1193 n8
.add_dependency([n3
])
1194 n7
.add_dependency([n8
])
1196 def cycle(node
, stack
) -> None:
1197 global cycle_detected
1200 global cycle_detected
1202 nw
= SCons
.Node
.Walker(n3
, cycle_func
= cycle
)
1204 assert n
.name
== "n6", n
.name
1206 assert n
.name
== "n8", n
.name
1207 assert cycle_detected
1208 cycle_detected
= None
1210 assert n
.name
== "n7", n
.name
1212 assert nw
.get_next() is None
1214 def test_abspath(self
) -> None:
1215 """Test the get_abspath() method."""
1217 assert n
.get_abspath() == str(n
), n
.get_abspath()
1219 def test_for_signature(self
) -> None:
1220 """Test the for_signature() method."""
1222 assert n
.for_signature() == str(n
), n
.get_abspath()
1224 def test_get_string(self
) -> None:
1225 """Test the get_string() method."""
1226 class TestNode(MyNode
):
1227 def __init__(self
, name
, sig
) -> None:
1228 super().__init
__(name
)
1231 def for_signature(self
):
1234 n
= TestNode("foo", "bar")
1235 assert n
.get_string(0) == "foo", n
.get_string(0)
1236 assert n
.get_string(1) == "bar", n
.get_string(1)
1238 def test_literal(self
) -> None:
1239 """Test the is_literal() function."""
1241 assert n
.is_literal()
1243 def test_sconscripts(self
) -> None:
1244 """Test the is_sconscript() function."""
1245 # check nodes are not sconscript unless added to the list
1247 n2
=SCons
.Node
.Node()
1248 assert not n
.is_sconscript()
1249 assert not n2
.is_sconscript()
1251 # add node to sconscript list and verify
1252 SCons
.Node
.SConscriptNodes
.add(n2
)
1253 assert not n
.is_sconscript()
1254 assert n2
.is_sconscript()
1256 def test_conftests(self
) -> None:
1257 """Test the is_conftest() function."""
1258 # check nodes are not sconscript unless added to the list
1260 n2
=SCons
.Node
.Node()
1261 assert not n
.is_conftest()
1262 assert not n2
.is_conftest()
1264 # add node to sconscript list and verify
1265 n2
.attributes
.conftest_node
= 1
1266 assert not n
.is_conftest()
1267 assert n2
.is_conftest()
1269 def test_Annotate(self
) -> None:
1270 """Test using an interface-specific Annotate function."""
1271 def my_annotate(node
, self
=self
) -> None:
1272 node
.Tag('annotation', self
.node_string
)
1274 save_Annotate
= SCons
.Node
.Annotate
1275 SCons
.Node
.Annotate
= my_annotate
1278 self
.node_string
= '#1'
1279 n
= SCons
.Node
.Node()
1280 a
= n
.GetTag('annotation')
1283 self
.node_string
= '#2'
1284 n
= SCons
.Node
.Node()
1285 a
= n
.GetTag('annotation')
1288 SCons
.Node
.Annotate
= save_Annotate
1290 def test_clear(self
) -> None:
1291 """Test clearing all cached state information."""
1292 n
= SCons
.Node
.Node()
1296 n
.includes
= 'testincludes'
1297 n
.Tag('found_includes', {'testkey':'testvalue'})
1298 n
.implicit
= 'testimplicit'
1306 assert n
.includes
is None, n
.includes
1307 assert n
.cached
== 0, n
.cached
1310 def test_get_subst_proxy(self
) -> None:
1311 """Test the get_subst_proxy method."""
1314 assert n
.get_subst_proxy() == n
, n
.get_subst_proxy()
1316 def test_new_binfo(self
) -> None:
1317 """Test the new_binfo() method"""
1318 n
= SCons
.Node
.Node()
1319 result
= n
.new_binfo()
1320 assert isinstance(result
, SCons
.Node
.BuildInfoBase
), result
1322 def test_get_suffix(self
) -> None:
1323 """Test the base Node get_suffix() method"""
1324 n
= SCons
.Node
.Node()
1328 def test_postprocess(self
) -> None:
1329 """Test calling the base Node postprocess() method"""
1330 n
= SCons
.Node
.Node()
1331 n
.waiting_parents
= {'foo', 'bar'}
1334 assert n
.waiting_parents
== set(), n
.waiting_parents
1336 def test_add_to_waiting_parents(self
) -> None:
1337 """Test the add_to_waiting_parents() method"""
1338 n1
= SCons
.Node
.Node()
1339 n2
= SCons
.Node
.Node()
1340 assert n1
.waiting_parents
== set(), n1
.waiting_parents
1341 r
= n1
.add_to_waiting_parents(n2
)
1343 assert n1
.waiting_parents
== {n2}
, n1
.waiting_parents
1344 r
= n1
.add_to_waiting_parents(n2
)
1348 class NodeListTestCase(unittest
.TestCase
):
1349 def test___str__(self
) -> None:
1354 nl
= SCons
.Node
.NodeList([n3
, n2
, n1
])
1357 ul
= collections
.UserList([2])
1359 assert s
== "['n3', 'n2', 'n1']", s
1362 r
= re
.sub(r
'at (0[xX])?[0-9a-fA-F]+', 'at 0x', r
)
1363 # Don't care about ancestry: just leaf value of MyNode
1364 r
= re
.sub(r
'<.*?\.MyNode', '<MyNode', r
)
1365 # New-style classes report as "object"; classic classes report
1367 r
= re
.sub("object", "instance", r
)
1368 l
= ", ".join(["<MyNode instance at 0x>"]*3)
1369 assert r
== '[%s]' % l
, r
1373 if __name__
== "__main__":
1379 # indent-tabs-mode:nil
1381 # vim: set expandtab tabstop=4 shiftwidth=4: