Skip to content

Commit 47798fe

Browse files
author
martin
committed
fetch and merge
2 parents 5134080 + 5bf439a commit 47798fe

208 files changed

Lines changed: 5332 additions & 1777 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
liberapay: TeamNewPipe
2+
custom: 'https://newpipe.net/donate/'

.github/workflows/ci.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ jobs:
5252
test-android:
5353
# macos has hardware acceleration. See android-emulator-runner action
5454
runs-on: macos-latest
55+
timeout-minutes: 20
5556
strategy:
5657
matrix:
5758
# api-level 19 is min sdk, but throws errors related to desugaring
@@ -73,6 +74,13 @@ jobs:
7374
# workaround to emulator bug: https://github.com/ReactiveCircus/android-emulator-runner/issues/160
7475
emulator-build: 7425822
7576
script: ./gradlew connectedCheck --stacktrace
77+
78+
- name: Upload test report when tests fail # because the printed out stacktrace (console) is too short, see also #7553
79+
uses: actions/upload-artifact@v2
80+
if: failure()
81+
with:
82+
name: android-test-report-api${{ matrix.api-level }}
83+
path: app/build/reports/androidTests/connected/**
7684

7785
sonar:
7886
runs-on: ubuntu-latest

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ captures/
88
*~
99
.weblate
1010
*.class
11-
**/debug/
12-
**/release/
11+
app/debug/
12+
app/release/
1313

1414
# vscode / eclipse files
1515
*.classpath

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<p align="center"><a href="https://newpipe.net">Website</a> &bull; <a href="https://newpipe.net/blog/">Blog</a> &bull; <a href="https://newpipe.net/FAQ/">FAQ</a> &bull; <a href="https://newpipe.net/press/">Press</a></p>
1818
<hr>
1919

20-
*Read this in other languages: [English](README.md), [Español](README.es.md), [한국어](README.ko.md), [Soomaali](README.so.md), [Português Brasil](README.pt_BR.md), [日本語](README.ja.md), [Română](README.ro.md), [Türkçe](README.tr.md).*
20+
*Read this in other languages: [English](README.md), [Español](doc/README.es.md), [한국어](doc/README.ko.md), [Soomaali](doc/README.so.md), [Português Brasil](doc/README.pt_BR.md), [Polski](doc/README.pl.md), [日本語](doc/README.ja.md), [Română](doc/README.ro.md), [Türkçe](doc/README.tr.md), [正體中文](doc/README.zh_TW.md).*
2121

2222
<b>WARNING: THIS IS A BETA VERSION, THEREFORE YOU MAY ENCOUNTER BUGS. IF YOU DO, OPEN AN ISSUE VIA OUR GITHUB REPOSITORY.</b>
2323

app/build.gradle

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ plugins {
88
}
99

1010
android {
11-
compileSdkVersion 30
11+
compileSdk 30
1212
buildToolsVersion '30.0.3'
1313

1414
defaultConfig {
1515
applicationId "org.schabi.newpipe"
1616
resValue "string", "app_name", "NewPipe"
17-
minSdkVersion 19
18-
targetSdkVersion 29
19-
versionCode 981
20-
versionName "0.21.15"
17+
minSdk 19
18+
targetSdk 29
19+
versionCode 982
20+
versionName "0.21.16"
2121

2222
multiDexEnabled true
2323

@@ -65,7 +65,7 @@ android {
6565
}
6666
}
6767

68-
lintOptions {
68+
lint {
6969
checkReleaseBuilds false
7070
// Or, if you prefer, you can continue to check for errors in release builds,
7171
// but continue the build even when errors are found:
@@ -98,7 +98,7 @@ android {
9898
}
9999

100100
ext {
101-
checkstyleVersion = '9.2'
101+
checkstyleVersion = '9.2.1'
102102

103103
androidxLifecycleVersion = '2.3.1'
104104
androidxRoomVersion = '2.3.0'
@@ -112,6 +112,7 @@ ext {
112112
leakCanaryVersion = '2.5'
113113
stethoVersion = '1.6.0'
114114
mockitoVersion = '4.0.0'
115+
assertJVersion = '3.22.0'
115116
}
116117

117118
configurations {
@@ -188,7 +189,7 @@ dependencies {
188189
// name and the commit hash with the commit hash of the (pushed) commit you want to test
189190
// This works thanks to JitPack: https://jitpack.io/
190191
implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751'
191-
implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.21.12'
192+
implementation 'com.github.TeamNewPipe:NewPipeExtractor:65129e6'
192193

193194
/** Checkstyle **/
194195
checkstyle "com.puppycrawl.tools:checkstyle:${checkstyleVersion}"
@@ -290,6 +291,7 @@ dependencies {
290291
androidTestImplementation "androidx.test.ext:junit:1.1.3"
291292
androidTestImplementation "androidx.test:runner:1.4.0"
292293
androidTestImplementation "androidx.room:room-testing:${androidxRoomVersion}"
294+
androidTestImplementation "org.assertj:assertj-core:${assertJVersion}"
293295
}
294296

295297
static String getGitWorkingBranch() {
Lines changed: 80 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
package org.schabi.newpipe.local.history
22

33
import androidx.test.core.app.ApplicationProvider
4+
import org.assertj.core.api.Assertions.assertThat
45
import org.junit.After
56
import org.junit.Assert.assertEquals
6-
import org.junit.Assert.assertTrue
77
import org.junit.Before
88
import org.junit.Rule
99
import org.junit.Test
10-
import org.junit.rules.Timeout
1110
import org.schabi.newpipe.database.AppDatabase
1211
import org.schabi.newpipe.database.history.model.SearchHistoryEntry
1312
import org.schabi.newpipe.testUtil.TestDatabase
1413
import org.schabi.newpipe.testUtil.TrampolineSchedulerRule
14+
import java.time.LocalDateTime
1515
import java.time.OffsetDateTime
16-
import java.util.concurrent.TimeUnit
16+
import java.time.ZoneOffset
1717

1818
class HistoryRecordManagerTest {
1919

@@ -23,9 +23,6 @@ class HistoryRecordManagerTest {
2323
@get:Rule
2424
val trampolineScheduler = TrampolineSchedulerRule()
2525

26-
@get:Rule
27-
val timeout = Timeout(1, TimeUnit.SECONDS)
28-
2926
@Before
3027
fun setup() {
3128
database = TestDatabase.createReplacingNewPipeDatabase()
@@ -45,109 +42,137 @@ class HistoryRecordManagerTest {
4542
// that the number of Lists it returns is exactly 1, we can only check if the first List is
4643
// correct. Why on earth has a Flowable been used instead of a Single for getAll()?!?
4744
val entities = database.searchHistoryDAO().all.blockingFirst()
48-
assertEquals(1, entities.size)
49-
assertEquals(1, entities[0].id)
50-
assertEquals(0, entities[0].serviceId)
51-
assertEquals("Hello", entities[0].search)
45+
assertThat(entities).hasSize(1)
46+
assertThat(entities[0].id).isEqualTo(1)
47+
assertThat(entities[0].serviceId).isEqualTo(0)
48+
assertThat(entities[0].search).isEqualTo("Hello")
5249
}
5350

5451
@Test
5552
fun deleteSearchHistory() {
5653
val entries = listOf(
57-
SearchHistoryEntry(OffsetDateTime.now(), 0, "A"),
58-
SearchHistoryEntry(OffsetDateTime.now(), 2, "A"),
59-
SearchHistoryEntry(OffsetDateTime.now(), 1, "B"),
60-
SearchHistoryEntry(OffsetDateTime.now(), 0, "B"),
54+
SearchHistoryEntry(time.minusSeconds(1), 0, "A"),
55+
SearchHistoryEntry(time.minusSeconds(2), 2, "A"),
56+
SearchHistoryEntry(time.minusSeconds(3), 1, "B"),
57+
SearchHistoryEntry(time.minusSeconds(4), 0, "B"),
6158
)
6259

6360
// make sure all 4 were inserted
6461
database.searchHistoryDAO().insertAll(entries)
65-
assertEquals(entries.size, database.searchHistoryDAO().all.blockingFirst().size)
62+
assertThat(database.searchHistoryDAO().all.blockingFirst()).hasSameSizeAs(entries)
6663

6764
// try to delete only "A" entries, "B" entries should be untouched
6865
manager.deleteSearchHistory("A").test().await().assertValue(2)
6966
val entities = database.searchHistoryDAO().all.blockingFirst()
70-
assertEquals(2, entities.size)
71-
assertTrue(entries[2].hasEqualValues(entities[0]))
72-
assertTrue(entries[3].hasEqualValues(entities[1]))
67+
assertThat(entities).hasSize(2)
68+
assertThat(entities).usingElementComparator { o1, o2 -> if (o1.hasEqualValues(o2)) 0 else 1 }
69+
.containsExactly(*entries.subList(2, 4).toTypedArray())
7370

7471
// assert that nothing happens if we delete a search query that does exist in the db
7572
manager.deleteSearchHistory("A").test().await().assertValue(0)
7673
val entities2 = database.searchHistoryDAO().all.blockingFirst()
77-
assertEquals(2, entities2.size)
78-
assertTrue(entries[2].hasEqualValues(entities2[0]))
79-
assertTrue(entries[3].hasEqualValues(entities2[1]))
74+
assertThat(entities2).hasSize(2)
75+
assertThat(entities2).usingElementComparator { o1, o2 -> if (o1.hasEqualValues(o2)) 0 else 1 }
76+
.containsExactly(*entries.subList(2, 4).toTypedArray())
8077

8178
// delete all remaining entries
8279
manager.deleteSearchHistory("B").test().await().assertValue(2)
83-
assertEquals(0, database.searchHistoryDAO().all.blockingFirst().size)
80+
assertThat(database.searchHistoryDAO().all.blockingFirst()).isEmpty()
8481
}
8582

8683
@Test
8784
fun deleteCompleteSearchHistory() {
8885
val entries = listOf(
89-
SearchHistoryEntry(OffsetDateTime.now(), 1, "A"),
90-
SearchHistoryEntry(OffsetDateTime.now(), 2, "B"),
91-
SearchHistoryEntry(OffsetDateTime.now(), 0, "C"),
86+
SearchHistoryEntry(time.minusSeconds(1), 1, "A"),
87+
SearchHistoryEntry(time.minusSeconds(2), 2, "B"),
88+
SearchHistoryEntry(time.minusSeconds(3), 0, "C"),
9289
)
9390

9491
// make sure all 3 were inserted
9592
database.searchHistoryDAO().insertAll(entries)
96-
assertEquals(entries.size, database.searchHistoryDAO().all.blockingFirst().size)
93+
assertThat(database.searchHistoryDAO().all.blockingFirst()).hasSameSizeAs(entries)
9794

9895
// should remove everything
9996
manager.deleteCompleteSearchHistory().test().await().assertValue(entries.size)
100-
assertEquals(0, database.searchHistoryDAO().all.blockingFirst().size)
97+
assertThat(database.searchHistoryDAO().all.blockingFirst()).isEmpty()
10198
}
10299

103-
@Test
104-
fun getRelatedSearches_emptyQuery() {
100+
private fun insertShuffledRelatedSearches(relatedSearches: Collection<SearchHistoryEntry>) {
101+
102+
// shuffle to make sure the order of items returned by queries depends only on
103+
// SearchHistoryEntry.creationDate, not on the actual insertion time, so that we can
104+
// verify that the `ORDER BY` clause does its job
105+
database.searchHistoryDAO().insertAll(relatedSearches.shuffled())
106+
105107
// make sure all entries were inserted
106-
database.searchHistoryDAO().insertAll(RELATED_SEARCHES_ENTRIES)
107108
assertEquals(
108-
RELATED_SEARCHES_ENTRIES.size,
109+
relatedSearches.size,
109110
database.searchHistoryDAO().all.blockingFirst().size
110111
)
112+
}
113+
114+
@Test
115+
fun getRelatedSearches_emptyQuery() {
116+
insertShuffledRelatedSearches(RELATED_SEARCHES_ENTRIES)
111117

112118
// make sure correct number of searches is returned and in correct order
113119
val searches = manager.getRelatedSearches("", 6, 4).blockingFirst()
114-
assertEquals(4, searches.size)
115-
assertEquals(RELATED_SEARCHES_ENTRIES[6].search, searches[0]) // A (even if in two places)
116-
assertEquals(RELATED_SEARCHES_ENTRIES[4].search, searches[1]) // B
117-
assertEquals(RELATED_SEARCHES_ENTRIES[5].search, searches[2]) // AA
118-
assertEquals(RELATED_SEARCHES_ENTRIES[2].search, searches[3]) // BA
120+
assertThat(searches).containsExactly(
121+
RELATED_SEARCHES_ENTRIES[6].search, // A (even if in two places)
122+
RELATED_SEARCHES_ENTRIES[4].search, // B
123+
RELATED_SEARCHES_ENTRIES[5].search, // AA
124+
RELATED_SEARCHES_ENTRIES[2].search, // BA
125+
)
119126
}
120127

121128
@Test
122-
fun getRelatedSearched_nonEmptyQuery() {
123-
// make sure all entries were inserted
124-
database.searchHistoryDAO().insertAll(RELATED_SEARCHES_ENTRIES)
125-
assertEquals(
126-
RELATED_SEARCHES_ENTRIES.size,
127-
database.searchHistoryDAO().all.blockingFirst().size
129+
fun getRelatedSearches_emptyQuery_manyDuplicates() {
130+
insertShuffledRelatedSearches(
131+
listOf(
132+
SearchHistoryEntry(time.minusSeconds(9), 3, "A"),
133+
SearchHistoryEntry(time.minusSeconds(8), 3, "AB"),
134+
SearchHistoryEntry(time.minusSeconds(7), 3, "A"),
135+
SearchHistoryEntry(time.minusSeconds(6), 3, "A"),
136+
SearchHistoryEntry(time.minusSeconds(5), 3, "BA"),
137+
SearchHistoryEntry(time.minusSeconds(4), 3, "A"),
138+
SearchHistoryEntry(time.minusSeconds(3), 3, "A"),
139+
SearchHistoryEntry(time.minusSeconds(2), 0, "A"),
140+
SearchHistoryEntry(time.minusSeconds(1), 2, "AA"),
141+
)
128142
)
129143

144+
val searches = manager.getRelatedSearches("", 9, 3).blockingFirst()
145+
assertThat(searches).containsExactly("AA", "A", "BA")
146+
}
147+
148+
@Test
149+
fun getRelatedSearched_nonEmptyQuery() {
150+
insertShuffledRelatedSearches(RELATED_SEARCHES_ENTRIES)
151+
130152
// make sure correct number of searches is returned and in correct order
131153
val searches = manager.getRelatedSearches("A", 3, 5).blockingFirst()
132-
assertEquals(3, searches.size)
133-
assertEquals(RELATED_SEARCHES_ENTRIES[6].search, searches[0]) // A (even if in two places)
134-
assertEquals(RELATED_SEARCHES_ENTRIES[5].search, searches[1]) // AA
135-
assertEquals(RELATED_SEARCHES_ENTRIES[1].search, searches[2]) // BA
154+
assertThat(searches).containsExactly(
155+
RELATED_SEARCHES_ENTRIES[6].search, // A (even if in two places)
156+
RELATED_SEARCHES_ENTRIES[5].search, // AA
157+
RELATED_SEARCHES_ENTRIES[1].search, // BA
158+
)
136159

137160
// also make sure that the string comparison is case insensitive
138161
val searches2 = manager.getRelatedSearches("a", 3, 5).blockingFirst()
139-
assertEquals(searches, searches2)
162+
assertThat(searches).isEqualTo(searches2)
140163
}
141164

142165
companion object {
143-
val RELATED_SEARCHES_ENTRIES = listOf(
144-
SearchHistoryEntry(OffsetDateTime.now().minusSeconds(7), 2, "AC"),
145-
SearchHistoryEntry(OffsetDateTime.now().minusSeconds(6), 0, "ABC"),
146-
SearchHistoryEntry(OffsetDateTime.now().minusSeconds(5), 1, "BA"),
147-
SearchHistoryEntry(OffsetDateTime.now().minusSeconds(4), 3, "A"),
148-
SearchHistoryEntry(OffsetDateTime.now().minusSeconds(2), 0, "B"),
149-
SearchHistoryEntry(OffsetDateTime.now().minusSeconds(3), 2, "AA"),
150-
SearchHistoryEntry(OffsetDateTime.now().minusSeconds(1), 1, "A"),
166+
private val time = OffsetDateTime.of(LocalDateTime.of(2000, 1, 1, 1, 1), ZoneOffset.UTC)
167+
168+
private val RELATED_SEARCHES_ENTRIES = listOf(
169+
SearchHistoryEntry(time.minusSeconds(7), 2, "AC"),
170+
SearchHistoryEntry(time.minusSeconds(6), 0, "ABC"),
171+
SearchHistoryEntry(time.minusSeconds(5), 1, "BA"),
172+
SearchHistoryEntry(time.minusSeconds(4), 3, "A"),
173+
SearchHistoryEntry(time.minusSeconds(2), 0, "B"),
174+
SearchHistoryEntry(time.minusSeconds(3), 2, "AA"),
175+
SearchHistoryEntry(time.minusSeconds(1), 1, "A"),
151176
)
152177
}
153178
}

app/src/androidTest/java/org/schabi/newpipe/local/playlist/LocalPlaylistManagerTest.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@ import org.junit.After
44
import org.junit.Before
55
import org.junit.Rule
66
import org.junit.Test
7-
import org.junit.rules.Timeout
87
import org.schabi.newpipe.database.AppDatabase
98
import org.schabi.newpipe.database.stream.model.StreamEntity
109
import org.schabi.newpipe.extractor.stream.StreamType
1110
import org.schabi.newpipe.testUtil.TestDatabase
1211
import org.schabi.newpipe.testUtil.TrampolineSchedulerRule
13-
import java.util.concurrent.TimeUnit
1412

1513
class LocalPlaylistManagerTest {
1614

@@ -20,9 +18,6 @@ class LocalPlaylistManagerTest {
2018
@get:Rule
2119
val trampolineScheduler = TrampolineSchedulerRule()
2220

23-
@get:Rule
24-
val timeout = Timeout(1, TimeUnit.SECONDS)
25-
2621
@Before
2722
fun setup() {
2823
database = TestDatabase.createReplacingNewPipeDatabase()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.schabi.newpipe.settings;
2+
3+
import android.content.Intent;
4+
5+
import leakcanary.LeakCanary;
6+
7+
/**
8+
* Build variant dependent (BVD) leak canary API implementation for the debug settings fragment.
9+
* This class is loaded via reflection by
10+
* {@link DebugSettingsFragment.DebugSettingsBVDLeakCanaryAPI}.
11+
*/
12+
@SuppressWarnings("unused") // Class is used but loaded via reflection
13+
public class DebugSettingsBVDLeakCanary
14+
implements DebugSettingsFragment.DebugSettingsBVDLeakCanaryAPI {
15+
16+
@Override
17+
public Intent getNewLeakDisplayActivityIntent() {
18+
return LeakCanary.INSTANCE.newLeakDisplayActivityIntent();
19+
}
20+
}

0 commit comments

Comments
 (0)