Coverage for tests/test_utilities.py: 100%

92 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-30 23:02 +0000

1"""Tests for `bunches.utilities`.""" 

2 

3from __future__ import annotations 

4 

5import dataclasses 

6 

7import pytest 

8 

9from bunches import Dictionary, Listing, utilities 

10 

11from .conftest import Something, Unnamed 

12 

13 

14def test_capitalify() -> None: 

15 """Tests `_capitalify`.""" 

16 assert utilities._capitalify('snake_case_name') == 'SnakeCaseName' 

17 assert utilities._capitalify('word') == 'Word' 

18 assert utilities._capitalify('') == '' 

19 

20 

21def test_snakify() -> None: 

22 """Tests `_snakify`.""" 

23 assert utilities._snakify('SnakeCaseName') == 'snake_case_name' 

24 assert utilities._snakify('Word') == 'word' 

25 assert utilities._snakify('HTTPServer') == 'http_server' 

26 assert utilities._snakify('already_snake') == 'already_snake' 

27 

28 

29def test_is_sequence() -> None: 

30 """Tests `_is_sequence`.""" 

31 assert utilities._is_sequence([1, 2]) 

32 assert utilities._is_sequence((1, 2)) 

33 assert utilities._is_sequence(list) 

34 assert not utilities._is_sequence('abc') 

35 assert not utilities._is_sequence(str) 

36 assert not utilities._is_sequence(b'abc') 

37 assert not utilities._is_sequence({'a': 1}) 

38 assert not utilities._is_sequence({1, 2}) 

39 assert not utilities._is_sequence(5) 

40 

41 

42def test_iterify() -> None: 

43 """Tests `_iterify`.""" 

44 assert list(utilities._iterify(None)) == [] 

45 assert list(utilities._iterify('abc')) == ['abc'] 

46 assert list(utilities._iterify(b'abc')) == [b'abc'] 

47 assert list(utilities._iterify([1, 2])) == [1, 2] 

48 assert list(utilities._iterify((1, 2))) == [1, 2] 

49 assert list(utilities._iterify(5)) == [5] 

50 assert list(utilities._iterify({'a': 1})) == ['a'] 

51 

52 

53def test_namify() -> None: 

54 """Tests `_namify`.""" 

55 

56 @dataclasses.dataclass 

57 class BadName: 

58 name: int = 3 

59 

60 assert utilities._namify('name') == 'name' 

61 assert utilities._namify(Something()) == 'something' 

62 assert utilities._namify(Something('other')) == 'other' 

63 assert utilities._namify(Unnamed()) == 'unnamed' 

64 assert utilities._namify(Unnamed) == 'unnamed' 

65 assert utilities._namify(Something) == 'something' 

66 assert utilities._namify(test_namify) == 'test_namify' 

67 assert utilities._namify(5) == 'int' 

68 assert utilities._namify(BadName()) == 'bad_name' 

69 

70 

71def test_namify_default() -> None: 

72 """Tests the `default` argument of `_namify`.""" 

73 

74 class Meta(type): 

75 """Metaclass whose classes have no usable name.""" 

76 

77 @property 

78 def __name__(cls) -> str: # type: ignore[override] 

79 """Returns an empty name. 

80 

81 Returns: 

82 An empty `str`. 

83 

84 """ 

85 return '' 

86 

87 class Nameless(metaclass = Meta): 

88 """Class without a usable name.""" 

89 

90 assert utilities._namify(Nameless(), default = 'fallback') == 'fallback' 

91 assert utilities._namify(Nameless()) is None 

92 

93 

94def test_return_subset() -> None: 

95 """Tests `_return_subset`.""" 

96 dictionary = Dictionary({'a': 1, 'b': 2}, default_factory = 7) 

97 subset = {'a': 1} 

98 result = utilities._return_subset(subset, dictionary, 'class') 

99 assert isinstance(result, Dictionary) 

100 assert result.contents == subset 

101 assert result.default_factory is None 

102 result = utilities._return_subset(subset, dictionary, 'copy') 

103 assert isinstance(result, Dictionary) 

104 assert result.contents == subset 

105 assert result.default_factory == 7 

106 assert result is not dictionary 

107 assert dictionary.contents == {'a': 1, 'b': 2} 

108 assert utilities._return_subset(subset, dictionary, 'simple') is subset 

109 with pytest.raises(ValueError, match = 'returns argument'): 

110 utilities._return_subset( 

111 subset, dictionary, 'other') # type: ignore[arg-type] 

112 listing = Listing([1, 2]) 

113 assert utilities._return_subset([1], listing, 'class') == Listing([1]) 

114 

115 

116def test_uniquify() -> None: 

117 """Tests `_uniquify`.""" 

118 assert utilities._uniquify('key', {}) == 'key' 

119 assert utilities._uniquify('key', {'other': 1}) == 'key' 

120 assert utilities._uniquify('key', {'key': 1}) == 'key2' 

121 assert utilities._uniquify('key', {'key': 1, 'key2': 1}) == 'key3' 

122 existing = {'key': 1} | {f'key{i}': 1 for i in range(2, 12)} 

123 assert utilities._uniquify('key', existing) == 'key12' 

124 assert utilities._uniquify('key', {'key': 1}, index = 4) == 'key5' 

125 

126 

127def test_uniquify_index() -> None: 

128 """Tests `_uniquify` with keys that end in the starting index.""" 

129 assert utilities._uniquify('v4', {'v4': 1}, index = 4) == 'v45' 

130 assert utilities._uniquify('a', {'a': 1, 'a1': 1}, index = 0) == 'a2' 

131 assert utilities._uniquify('a', {'a': 1}, index = 0) == 'a1' 

132 

133 

134def test_is_sequence_bunches() -> None: 

135 """Tests `_is_sequence` with `bunches` classes.""" 

136 assert utilities._is_sequence(Listing([1])) 

137 assert utilities._is_sequence(range(3)) 

138 assert not utilities._is_sequence(Dictionary({'a': 1})) 

139 

140 

141def test_namify_class_with_name_attribute() -> None: 

142 """Tests that a class's `name` attribute is not used for the class.""" 

143 

144 class Named: 

145 """Class with a `name` class attribute.""" 

146 

147 name = 'instance_name' 

148 

149 assert utilities._namify(Named()) == 'instance_name' 

150 assert utilities._namify(Named) == 'named'