|
2 | 2 | // for details. All rights reserved. Use of this source code is governed by a
|
3 | 3 | // BSD-style license that can be found in the LICENSE file.
|
4 | 4 |
|
5 |
| -import 'dart:math'; |
6 |
| - |
7 | 5 | import 'package:pub_dev/service/download_counts/package_trends.dart';
|
8 | 6 | import 'package:test/test.dart';
|
9 | 7 |
|
@@ -35,39 +33,33 @@ void main() {
|
35 | 33 |
|
36 | 34 | test('calculates positive relative growth rate for positive trend', () {
|
37 | 35 | // Input list (newest first): [1645, 1635, ..., 1355] (30 values)
|
38 |
| - // Average = 1500 for the first 30 values. Slope: 10. |
39 |
| - final downloads = <int>[ |
40 |
| - ...List<int>.generate(analysisWindowDays * 2, (i) => 1645 - (i * 10)), |
41 |
| - ...List.filled(300, 0) |
42 |
| - ]; |
43 |
| - final avg = downloads.reduce((prev, element) => prev + element) / 330; |
44 |
| - final expectedRate = 10.0 / avg; |
45 |
| - expect(computeRelativeGrowthRate(downloads), expectedRate); |
| 36 | + final downloads = |
| 37 | + List<int>.generate(analysisWindowDays, (i) => 1645 - (i * 10)); |
| 38 | + final expectedRate = 0.0066800225103267686; |
| 39 | + expect(computeRelativeGrowthRate(downloads), closeTo(expectedRate, 1e-9)); |
46 | 40 | });
|
47 | 41 |
|
48 | 42 | test('calculates negative relative growth rate for negative trend', () {
|
49 | 43 | // Input list (newest first): [1355, 1365, ..., 1645]
|
50 |
| - // Average = 1500. Slope: -10. |
51 | 44 | final downloads =
|
52 | 45 | List<int>.generate(analysisWindowDays, (i) => 1355 + (i * 10));
|
53 |
| - final expectedRate = -10.0 / 1500.0; |
54 |
| - expect(computeRelativeGrowthRate(downloads), expectedRate); |
| 46 | + final expectedRate = -0.0066800225103267686; |
| 47 | + expect(computeRelativeGrowthRate(downloads), closeTo(expectedRate, 1e-9)); |
55 | 48 | });
|
56 | 49 |
|
57 | 50 | test(
|
58 | 51 | 'calculates positive relative growth for data barely meeting threshold',
|
59 | 52 | () {
|
60 | 53 | // Input list (newest first): [1016, 1015, ..., 987]
|
61 |
| - // Average: 1001.5. Slope: 1. |
62 | 54 | final downloads =
|
63 | 55 | List<int>.generate(analysisWindowDays, (i) => 1016 - i * 1);
|
64 |
| - final expectedRate = 1.0 / 1001.5; |
| 56 | + final expectedRate = 0.000998546932871653; |
65 | 57 | expect(computeRelativeGrowthRate(downloads), closeTo(expectedRate, 1e-9));
|
66 | 58 | });
|
67 | 59 |
|
68 | 60 | test('should handle fluctuating data with a slight positive overall trend',
|
69 | 61 | () {
|
70 |
| - // Newest first. Average 1135. |
| 62 | + // Newest first. |
71 | 63 | final downloads = <int>[
|
72 | 64 | 1300,
|
73 | 65 | 1250,
|
@@ -100,91 +92,78 @@ void main() {
|
100 | 92 | 1020,
|
101 | 93 | 970
|
102 | 94 | ];
|
103 |
| - final expectedRate = 683250.0 / 67425.0 / 1135.0; |
104 |
| - expect(computeRelativeGrowthRate(downloads), expectedRate); |
| 95 | + final expectedRate = 0.008963997580330865; |
| 96 | + expect(computeRelativeGrowthRate(downloads), closeTo(expectedRate, 1e-9)); |
105 | 97 | });
|
106 | 98 | });
|
107 | 99 | group('computeTrendScore', () {
|
108 |
| - test('Short history, very low sum, positive growth -> heavily dampened', |
109 |
| - () { |
| 100 | + test('Short history, very low sum, -> heavily dampened', () { |
110 | 101 | final downloads = [100, 50];
|
111 |
| - // For relativeGrowth: |
112 |
| - // Padded data: [100, 50, 0...0] (28 zeros) |
113 |
| - // avg = (100 + 50) / 2 = 75. |
114 |
| - // growthRate = 63750 / 67425 |
115 |
| - final expectedDampening = min(1.0, 150 / 30000); |
116 |
| - final expectedRelativeGrowth = (63750 / 67425) / 75; |
117 |
| - final expectedScore = |
118 |
| - expectedRelativeGrowth * expectedDampening * expectedDampening; |
119 |
| - expect(computeTrendScore(downloads), expectedScore); |
| 102 | + final totalSum = 150; |
| 103 | + |
| 104 | + final expectedRelativeGrowth = 0.69315; |
| 105 | + final expectedDampening = |
| 106 | + calculateSigmoidScaleScore(total30Downloads: totalSum); |
| 107 | + final expectedScore = expectedRelativeGrowth * expectedDampening; |
| 108 | + |
| 109 | + expect(computeTrendScore(downloads), closeTo(expectedScore, 0.0001)); |
120 | 110 | });
|
121 |
| - }); |
122 | 111 |
|
123 |
| - test('Full history, sum meets threshold, positive growth -> no dampening', |
124 |
| - () { |
125 |
| - final downloads = |
126 |
| - List<int>.generate(analysisWindowDays, (i) => 1645 - (i * 10)); |
127 |
| - // For relativeGrowth: |
128 |
| - // data: [1645, 1635, ..., 1355] |
129 |
| - // avg = 1500, |
130 |
| - // growthrate = 10 |
131 |
| - final expectedDampening = min(1.0, 45000 / 30000); |
132 |
| - final expectedRelativeGrowth = 10 / 1500; |
133 |
| - final expectedScore = |
134 |
| - expectedRelativeGrowth * expectedDampening * expectedDampening; |
135 |
| - expect(computeTrendScore(downloads), expectedScore); |
136 |
| - }); |
| 112 | + test('Full history, positive growth -> almost no dampening', () { |
| 113 | + final downloads = // [1645, 1635, ..., 1355] |
| 114 | + List<int>.generate(analysisWindowDays, (i) => 1645 - (i * 10)); |
| 115 | + final totalSum = downloads.reduce((a, b) => a + b); // 45000 |
137 | 116 |
|
138 |
| - test('Negative growth, sum meets threshold -> no dampening', () { |
139 |
| - final downloads = |
140 |
| - List<int>.generate(analysisWindowDays, (i) => 1355 + (i * 10)); |
141 |
| - // For relativeGrowth: |
142 |
| - // data: [1645, 1635, ..., 1355] |
143 |
| - // avg = 1500, |
144 |
| - // growthrate = -10 |
145 |
| - final expectedDampening = min(1.0, 45000 / 30000); |
146 |
| - final expectedRelativeGrowth = -10.0 / 1500; |
147 |
| - final expectedScore = |
148 |
| - expectedRelativeGrowth * expectedDampening * expectedDampening; |
149 |
| - expect(computeTrendScore(downloads), expectedScore); |
150 |
| - }); |
151 |
| - test('Full history, sum below threshold, positive growth -> dampened', () { |
152 |
| - final downloads = |
153 |
| - List<int>.generate(analysisWindowDays, (i) => 645 - (i * 10)); |
154 |
| - // For relativeGrowth: |
155 |
| - // data: [645,..., 345, 355] |
156 |
| - // avg = 500 |
157 |
| - // growthrate = 10 |
158 |
| - final expectedDampening = min(1.0, 15000 / 30000); |
159 |
| - final expectedRelativeGrowth = 10.0 / 500.0; |
160 |
| - final expectedScore = |
161 |
| - expectedRelativeGrowth * expectedDampening * expectedDampening; |
162 |
| - |
163 |
| - expect(computeTrendScore(downloads), expectedScore); |
164 |
| - }); |
| 117 | + final expectedRelativeGrowth = 0.006673; |
| 118 | + final expectedDampening = |
| 119 | + calculateSigmoidScaleScore(total30Downloads: totalSum); |
| 120 | + final expectedScore = expectedRelativeGrowth * expectedDampening; |
165 | 121 |
|
166 |
| - test('Empty totalDownloads list -> score 0', () { |
167 |
| - final downloads = <int>[]; |
168 |
| - expect(computeTrendScore(downloads), 0); |
169 |
| - }); |
| 122 | + expect(computeTrendScore(downloads), closeTo(expectedScore, 0.0001)); |
| 123 | + }); |
170 | 124 |
|
171 |
| - test('Full history, all zero downloads -> score 0', () { |
172 |
| - final downloads = List<int>.filled(analysisWindowDays, 0); |
173 |
| - expect(computeTrendScore(downloads), 0); |
174 |
| - }); |
| 125 | + test('Full history, negative growth -> almost no dampening', () { |
| 126 | + final downloads = // [1355, 1365, ..., 1645] |
| 127 | + List<int>.generate(analysisWindowDays, (i) => 1355 + (i * 10)); |
| 128 | + final totalSum = downloads.reduce((a, b) => a + b); // 45000 |
| 129 | + final expectedRelativeGrowth = -0.006673; |
| 130 | + final expectedDampening = |
| 131 | + calculateSigmoidScaleScore(total30Downloads: totalSum); |
| 132 | + final expectedScore = expectedRelativeGrowth * expectedDampening; |
175 | 133 |
|
176 |
| - test('ThirtyDaySum just below threshold correctly, flat growth', () { |
177 |
| - final downloads = List<int>.filled(analysisWindowDays, 999); |
178 |
| - expect(computeTrendScore(downloads), 0); |
179 |
| - }); |
| 134 | + expect(computeTrendScore(downloads), closeTo(expectedScore, 0.0001)); |
| 135 | + }); |
| 136 | + |
| 137 | + test('Full history, sum below threshold, positive growth -> dampened', () { |
| 138 | + final downloads = // [645, ... , 355] |
| 139 | + List<int>.generate(analysisWindowDays, (i) => 645 - (i * 10)); |
| 140 | + final totalSum = downloads.reduce((a, b) => a + b); |
| 141 | + final expectedRelativeGrowth = 0.020373587410745377; |
| 142 | + final expectedDampening = |
| 143 | + calculateSigmoidScaleScore(total30Downloads: totalSum); |
| 144 | + final expectedScore = expectedRelativeGrowth * expectedDampening; |
| 145 | + |
| 146 | + expect(computeTrendScore(downloads), closeTo(expectedScore, 0.0001)); |
| 147 | + }); |
| 148 | + |
| 149 | + test('Empty totalDownloads list -> score 0', () { |
| 150 | + final downloads = <int>[]; |
| 151 | + expect(computeTrendScore(downloads), 0); |
| 152 | + }); |
180 | 153 |
|
181 |
| - test('Short history, high sum meets threshold -> no dampening', () { |
182 |
| - final downloads = List<int>.filled(15, 2000); |
183 |
| - final expectedDampening = min(1.0, 30000 / 30000); |
184 |
| - final expectedRelativeGrowth = (6750000 / 67425) / 2000; |
185 |
| - final expectedScore = |
186 |
| - expectedRelativeGrowth * expectedDampening * expectedDampening; |
| 154 | + test('Full history, all zero downloads -> score 0', () { |
| 155 | + final downloads = List<int>.filled(analysisWindowDays, 0); |
| 156 | + expect(computeTrendScore(downloads), 0); |
| 157 | + }); |
187 | 158 |
|
188 |
| - expect(computeTrendScore(downloads), expectedScore); |
| 159 | + test('Full history, sum just below threshold, flat growth', () { |
| 160 | + final downloads = List<int>.filled(analysisWindowDays, 999); |
| 161 | + expect(computeTrendScore(downloads), closeTo(0.0, 0.0001)); |
| 162 | + }); |
| 163 | + |
| 164 | + test('Short history, high sum meets threshold, flat growth', () { |
| 165 | + final downloads = List<int>.filled(15, 2000); |
| 166 | + expect(computeTrendScore(downloads), closeTo(0.0, 0.0001)); |
| 167 | + }); |
189 | 168 | });
|
190 | 169 | }
|
0 commit comments