From a3d0091e063e642fa176066572fd677f92c2be73 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 1 Aug 2019 01:10:05 +0200 Subject: [PATCH 01/16] Add NewPipeTestRunner to prevent failed tests with working code It works the same as the default junit runner except for these things: - when a test function throws a `ReCaptchaException` the test is ignored with a message and a stack trace. - when the failedTests/totalNotIgnoredTests ratio is above `errorRatioTriggeringIgnore`, all failing tests for that class are ignored. Probably YouTube returned something wrong. - The time it takes to conduct any test is displayed as 0ms --- .../org/schabi/newpipe/NewPipeTestRunner.java | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java new file mode 100644 index 0000000000..be5c9f3542 --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java @@ -0,0 +1,282 @@ +package org.schabi.newpipe; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.TestTimedOutException; +import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class NewPipeTestRunner extends Runner { + private static final float errorRatioTriggeringIgnore = 0.6f; + + private class TestException extends Exception { + TestException(Throwable throwable) { + super(throwable); + } + } + + + private class MethodResultCollector { + boolean ignoredByUser; + String methodName; + Throwable thrownException; + + MethodResultCollector(Method method, Object testClassInstance) throws IllegalAccessException { + ignoredByUser = method.isAnnotationPresent(Ignore.class); + methodName = method.getName(); + thrownException = null; + if (ignoredByUser) return; + + Test testAnnotation = method.getAnnotation(Test.class); + Class expectedThrowable = testAnnotation.expected(); + long timeout = testAnnotation.timeout(); + + try { + invokeAllMethods(beforeMethods, testClassInstance); + invokeCheckingTimeAndExceptions(method, testClassInstance, timeout, expectedThrowable); + invokeAllMethods(afterMethods, testClassInstance); + } catch (InvocationTargetException e) { + thrownException = e.getCause(); + } catch (TestException e) { + thrownException = e.getCause(); + } + } + + + boolean isIgnoredByUser() { + return ignoredByUser; + } + + boolean isSuccessful() { + return thrownException == null; + } + + + void showResults(RunNotifier notifier, boolean ignoreAnyError) { + Description methodDescription = Description.createTestDescription(testClass, methodName); + + if (ignoredByUser) { + notifier.fireTestIgnored(methodDescription); + System.out.println(methodName + "() ignored because of @Ignore"); + + } else { + if (thrownException == null) { + notifier.fireTestStarted(methodDescription); + notifier.fireTestFinished(methodDescription); + + } else if (thrownException instanceof ReCaptchaException) { + notifier.fireTestIgnored(methodDescription); + System.out.println(methodName + "() ignored since it threw a ReCaptchaException"); + thrownException.printStackTrace(System.out); + + } else if (ignoreAnyError) { + notifier.fireTestIgnored(methodDescription); + System.out.println(methodName + "() ignored since the whole class " + testClass.getName() + + " has more than " + (int)(errorRatioTriggeringIgnore*100) + "% of failed tests"); + thrownException.printStackTrace(System.out); + + } else { + notifier.fireTestStarted(methodDescription); + notifier.fireTestFailure(new Failure(methodDescription, thrownException)); + notifier.fireTestFinished(methodDescription); + + } + } + } + + } + + + private Class testClass; + private final ArrayList testMethods, + beforeMethods, afterMethods, + beforeClassMethods, afterClassMethods; + + public NewPipeTestRunner(Class testClass) throws InitializationError { + this.testClass = testClass; + Method[] allMethods = testClass.getDeclaredMethods(); + + testMethods = new ArrayList<>(); + beforeMethods = new ArrayList<>(); + afterMethods = new ArrayList<>(); + beforeClassMethods = new ArrayList<>(); + afterClassMethods = new ArrayList<>(); + + for (Method method : allMethods) { + if (method.isAnnotationPresent(Test.class)) { + validatePublicVoidNoArg(method, false); + testMethods.add(method); + + } else if (method.isAnnotationPresent(Before.class)) { + validatePublicVoidNoArg(method, false); + beforeMethods.add(method); + + } else if (method.isAnnotationPresent(After.class)) { + validatePublicVoidNoArg(method, false); + afterMethods.add(method); + + } else if (method.isAnnotationPresent(BeforeClass.class)) { + validatePublicVoidNoArg(method, true); + beforeClassMethods.add(method); + + } else if (method.isAnnotationPresent(AfterClass.class)) { + validatePublicVoidNoArg(method, true); + afterClassMethods.add(method); + + } + } + } + + + @Override + public Description getDescription() { + return Description.createTestDescription(testClass, "NewPipe custom runner"); + } + + + private static void validatePublicVoidNoArg(Method method, boolean shouldBeStatic) throws InitializationError { + List errors = new ArrayList<>(); + + if (method.getParameterTypes().length != 0) { + errors.add(new Exception("Method " + method.getName() + " should have no parameters")); + } + if (Modifier.isStatic(method.getModifiers()) != shouldBeStatic) { + String state = shouldBeStatic ? "should" : "should not"; + errors.add(new Exception("Method " + method.getName() + "() " + state + " be static")); + } + if (!Modifier.isPublic(method.getModifiers())) { + errors.add(new Exception("Method " + method.getName() + "() should be public")); + } + if (method.getReturnType() != Void.TYPE) { + errors.add(new Exception("Method " + method.getName() + "() should be void")); + } + + if (!errors.isEmpty()) { + throw new InitializationError(errors); + } + } + + private static void invokeAllMethods(List methods, Object testClassInstance) throws InvocationTargetException, IllegalAccessException { + for (Method method : methods) { + method.invoke(testClassInstance); + } + } + + abstract class RunnableCollectingThrowables implements Runnable { + Throwable collectedThrowable; + + abstract void runWithExceptions() throws Throwable; + + @Override + public final void run() { + try { + runWithExceptions(); + } catch (Throwable e) { + collectedThrowable = e; + } + } + + void throwCollectedThrowableIfPresent() throws Throwable { + if (collectedThrowable != null) { + throw collectedThrowable; + } + } + } + + private void invokeWithTimeout(final Method method, final Object testClassInstance, long timeout) throws InvocationTargetException, IllegalAccessException, TestException { + if (timeout > 0) { + final ExecutorService executorService = Executors.newSingleThreadExecutor(); + RunnableCollectingThrowables runnable = new RunnableCollectingThrowables() { + @Override + void runWithExceptions() throws Throwable { + method.invoke(testClassInstance); + } + }; + + try { + final Future f = (Future) executorService.submit(runnable); + f.get(timeout, TimeUnit.MILLISECONDS); + runnable.throwCollectedThrowableIfPresent(); + } catch (final TimeoutException e) { + throw new TestException(new TestTimedOutException(timeout, TimeUnit.MILLISECONDS)); + } catch (Throwable e) { + throw new TestException(e); + } finally { + executorService.shutdown(); + } + } else { + method.invoke(testClassInstance); + } + } + + private void invokeCheckingTimeAndExceptions(Method method, Object testClassInstance, long timeout, Class expectedThrowable) throws InvocationTargetException, IllegalAccessException, TestException { + boolean complete = false; + try { + invokeWithTimeout(method, testClassInstance, timeout); + complete = true; + } catch (InvocationTargetException e) { + if (expectedThrowable.equals(Test.None.class)) { + throw e; + } else if (!expectedThrowable.isInstance(e.getCause())) { + String message = "Unexpected exception, expected <" + expectedThrowable.getName() + + "> but was <" + e.getCause().getClass().getName() + ">"; + throw new TestException(new Exception(message, e)); + } + } + + if (complete && !expectedThrowable.equals(Test.None.class)) { + String message = "Expected exception <" + expectedThrowable.getName() + ">"; + throw new TestException(new Exception(message)); + } + } + + @Override + public void run(RunNotifier notifier) { + try { + Object testClassInstance = testClass.newInstance(); + invokeAllMethods(beforeClassMethods, testClassInstance); + + List savedResults = new ArrayList<>(); + for (Method testMethod : testMethods) { + savedResults.add(new MethodResultCollector(testMethod, testClassInstance)); + } + + int nrSuccessful = 0, nrNotIgnoredByUser = 0; + for (MethodResultCollector savedResult : savedResults) { + if (!savedResult.isIgnoredByUser()) { + ++nrNotIgnoredByUser; + if (savedResult.isSuccessful()) { + ++nrSuccessful; + } + } + } + + for (MethodResultCollector savedResult : savedResults) { + savedResult.showResults(notifier, (float)(nrNotIgnoredByUser - nrSuccessful) / nrNotIgnoredByUser >= errorRatioTriggeringIgnore); + } + + invokeAllMethods(afterClassMethods, testClassInstance); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} From 0667ca80daa88f1aa851898b274b221274afa7b7 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 1 Aug 2019 01:37:26 +0200 Subject: [PATCH 02/16] Add NewPipeTestRunnerOptions with failRatioTriggeringIgnore Instead of the constant variable used before, now the user can define it. For more info see documentation in NewPipeTestRunnerOptions.java --- .../org/schabi/newpipe/NewPipeTestRunner.java | 22 ++++++++++++++----- .../newpipe/NewPipeTestRunnerOptions.java | 17 ++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java index be5c9f3542..6c44c5704b 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java @@ -26,7 +26,6 @@ import java.util.concurrent.TimeoutException; public class NewPipeTestRunner extends Runner { - private static final float errorRatioTriggeringIgnore = 0.6f; private class TestException extends Exception { TestException(Throwable throwable) { @@ -91,7 +90,7 @@ void showResults(RunNotifier notifier, boolean ignoreAnyError) { } else if (ignoreAnyError) { notifier.fireTestIgnored(methodDescription); System.out.println(methodName + "() ignored since the whole class " + testClass.getName() + - " has more than " + (int)(errorRatioTriggeringIgnore*100) + "% of failed tests"); + " has more than " + (int)(failRatioTriggeringIgnore*100) + "% of failed tests"); thrownException.printStackTrace(System.out); } else { @@ -107,13 +106,14 @@ void showResults(RunNotifier notifier, boolean ignoreAnyError) { private Class testClass; + private float failRatioTriggeringIgnore; private final ArrayList testMethods, beforeMethods, afterMethods, beforeClassMethods, afterClassMethods; public NewPipeTestRunner(Class testClass) throws InitializationError { this.testClass = testClass; - Method[] allMethods = testClass.getDeclaredMethods(); + obtainRunnerOptions(); testMethods = new ArrayList<>(); beforeMethods = new ArrayList<>(); @@ -121,7 +121,7 @@ public NewPipeTestRunner(Class testClass) throws InitializationError { beforeClassMethods = new ArrayList<>(); afterClassMethods = new ArrayList<>(); - for (Method method : allMethods) { + for (Method method : testClass.getDeclaredMethods()) { if (method.isAnnotationPresent(Test.class)) { validatePublicVoidNoArg(method, false); testMethods.add(method); @@ -249,6 +249,18 @@ private void invokeCheckingTimeAndExceptions(Method method, Object testClassInst } } + + private void obtainRunnerOptions() { + if (testClass.isAnnotationPresent(NewPipeTestRunnerOptions.class)) { + NewPipeTestRunnerOptions options = (NewPipeTestRunnerOptions) testClass.getAnnotation(NewPipeTestRunnerOptions.class); + + failRatioTriggeringIgnore = options.failRatioTriggeringIgnore(); + } else { + throw new IllegalArgumentException("Test classes running with " + NewPipeTestRunner.class.getName() + " should also have @NewPipeTestRunnerOptions"); + } + } + + @Override public void run(RunNotifier notifier) { try { @@ -271,7 +283,7 @@ public void run(RunNotifier notifier) { } for (MethodResultCollector savedResult : savedResults) { - savedResult.showResults(notifier, (float)(nrNotIgnoredByUser - nrSuccessful) / nrNotIgnoredByUser >= errorRatioTriggeringIgnore); + savedResult.showResults(notifier, (float)(nrNotIgnoredByUser - nrSuccessful) / nrNotIgnoredByUser > failRatioTriggeringIgnore); } invokeAllMethods(afterClassMethods, testClassInstance); diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java new file mode 100644 index 0000000000..395bff0e1b --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java @@ -0,0 +1,17 @@ +package org.schabi.newpipe; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface NewPipeTestRunnerOptions { + /** + * The ratio between the number of failed tests and the total number + * of tests that have not been {@link org.junit.Ignore}d by the user. + * Above this ratio the Runner will ignore all failing tests, since + * there probably is a problem with YouTube blocking robots. A warning + * along with a stack trace are displayed anyway. + * @return the failedTests/notIgnoredTests ratio above which all failing tests are ignored + */ + float failRatioTriggeringIgnore(); +} From d553b3c9fbfad7077062d545c77f33db7dd973a7 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 1 Aug 2019 09:38:02 +0200 Subject: [PATCH 03/16] Improve exception handling in NewPipeTestRunner Now exceptions coming from the implementation are treated correctly (causing the program to crash) instead of only making the current test fail. --- .../org/schabi/newpipe/NewPipeTestRunner.java | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java index 6c44c5704b..33dbf9a4c8 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java @@ -19,6 +19,7 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -39,7 +40,7 @@ private class MethodResultCollector { String methodName; Throwable thrownException; - MethodResultCollector(Method method, Object testClassInstance) throws IllegalAccessException { + MethodResultCollector(Method method, Object testClassInstance) throws IllegalAccessException, ExecutionException, InterruptedException { ignoredByUser = method.isAnnotationPresent(Ignore.class); methodName = method.getName(); thrownException = null; @@ -181,36 +182,41 @@ private static void invokeAllMethods(List methods, Object testClassInsta } } - abstract class RunnableCollectingThrowables implements Runnable { - Throwable collectedThrowable; + class MethodRunnableCollectingExceptions implements Runnable { + InvocationTargetException collectedInvocationTargetException; + IllegalAccessException collectedIllegalAccessException; + Method method; + Object testClassInstance; - abstract void runWithExceptions() throws Throwable; + MethodRunnableCollectingExceptions(Method method, Object testClassInstance) { + this.method = method; + this.testClassInstance = testClassInstance; + } @Override public final void run() { try { - runWithExceptions(); - } catch (Throwable e) { - collectedThrowable = e; + method.invoke(testClassInstance); + } catch (InvocationTargetException e) { + collectedInvocationTargetException = e; + } catch (IllegalAccessException e) { + collectedIllegalAccessException = e; } } - void throwCollectedThrowableIfPresent() throws Throwable { - if (collectedThrowable != null) { - throw collectedThrowable; + void throwCollectedThrowableIfPresent() throws InvocationTargetException, IllegalAccessException { + if (collectedInvocationTargetException != null) { + throw collectedInvocationTargetException; + } else if (collectedIllegalAccessException != null) { + throw collectedIllegalAccessException; } } } - private void invokeWithTimeout(final Method method, final Object testClassInstance, long timeout) throws InvocationTargetException, IllegalAccessException, TestException { + private void invokeWithTimeout(final Method method, final Object testClassInstance, long timeout) throws InvocationTargetException, IllegalAccessException, TestException, InterruptedException, ExecutionException { if (timeout > 0) { final ExecutorService executorService = Executors.newSingleThreadExecutor(); - RunnableCollectingThrowables runnable = new RunnableCollectingThrowables() { - @Override - void runWithExceptions() throws Throwable { - method.invoke(testClassInstance); - } - }; + MethodRunnableCollectingExceptions runnable = new MethodRunnableCollectingExceptions(method, testClassInstance); try { final Future f = (Future) executorService.submit(runnable); @@ -218,8 +224,6 @@ void runWithExceptions() throws Throwable { runnable.throwCollectedThrowableIfPresent(); } catch (final TimeoutException e) { throw new TestException(new TestTimedOutException(timeout, TimeUnit.MILLISECONDS)); - } catch (Throwable e) { - throw new TestException(e); } finally { executorService.shutdown(); } @@ -228,7 +232,7 @@ void runWithExceptions() throws Throwable { } } - private void invokeCheckingTimeAndExceptions(Method method, Object testClassInstance, long timeout, Class expectedThrowable) throws InvocationTargetException, IllegalAccessException, TestException { + private void invokeCheckingTimeAndExceptions(Method method, Object testClassInstance, long timeout, Class expectedThrowable) throws InvocationTargetException, IllegalAccessException, TestException, ExecutionException, InterruptedException { boolean complete = false; try { invokeWithTimeout(method, testClassInstance, timeout); @@ -291,4 +295,5 @@ public void run(RunNotifier notifier) { throw new RuntimeException(e); } } + } From 3b621a766276bc97d9cb0ba7237aad9a04ba1772 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 1 Aug 2019 09:55:15 +0200 Subject: [PATCH 04/16] Default value for failRatioTriggeringIgnore in NewPipeTestRunner It is >=1.0f so that it makes the runner never ignore any failed test, disabling the feature --- .../java/org/schabi/newpipe/NewPipeTestRunnerOptions.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java index 395bff0e1b..c582e10b8e 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java @@ -11,7 +11,11 @@ * Above this ratio the Runner will ignore all failing tests, since * there probably is a problem with YouTube blocking robots. A warning * along with a stack trace are displayed anyway. + *

+ * A value >= 1.0f means the same as "never ignore any failed test" + * A value <= 0.0 means the same as "ignore all failed tests" + * * @return the failedTests/notIgnoredTests ratio above which all failing tests are ignored */ - float failRatioTriggeringIgnore(); + float failRatioTriggeringIgnore() default 1.1f; } From c0ceec8e66739a4e94fa2c6833c09525f4569f84 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 1 Aug 2019 10:49:43 +0200 Subject: [PATCH 05/16] Add support for reason in @Ignore(...) to NewPipeTestRunner --- .../java/org/schabi/newpipe/NewPipeTestRunner.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java index 33dbf9a4c8..b343fc4c71 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java @@ -37,6 +37,7 @@ private class TestException extends Exception { private class MethodResultCollector { boolean ignoredByUser; + String ignoredByUserReason; String methodName; Throwable thrownException; @@ -44,7 +45,11 @@ private class MethodResultCollector { ignoredByUser = method.isAnnotationPresent(Ignore.class); methodName = method.getName(); thrownException = null; - if (ignoredByUser) return; + + if (ignoredByUser) { + ignoredByUserReason = method.getAnnotation(Ignore.class).value(); + return; + } Test testAnnotation = method.getAnnotation(Test.class); Class expectedThrowable = testAnnotation.expected(); @@ -76,7 +81,11 @@ void showResults(RunNotifier notifier, boolean ignoreAnyError) { if (ignoredByUser) { notifier.fireTestIgnored(methodDescription); - System.out.println(methodName + "() ignored because of @Ignore"); + if (ignoredByUserReason.isEmpty()) { + System.out.println(methodName + "() ignored because of @Ignore"); + } else { + System.out.println(methodName + "() ignored because of @Ignore: " + ignoredByUserReason); + } } else { if (thrownException == null) { From 7ea7c1b2c743aa03e4847a31bc683bd58c528de6 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 17 Aug 2019 10:55:54 +0200 Subject: [PATCH 06/16] Add assertResponseCodeOk to ExtractorAsserts --- .../schabi/newpipe/extractor/ExtractorAsserts.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java b/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java index 1006f7b34e..b17d1592cd 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/ExtractorAsserts.java @@ -2,6 +2,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; + +import java.io.IOException; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.List; @@ -20,6 +23,7 @@ public static void assertEmptyErrors(String message, List errors) { } } + @Nonnull private static URL urlFromString(String url) { try { @@ -38,6 +42,14 @@ public static void assertIsSecureUrl(String urlToCheck) { assertEquals("Protocol of URL is not secure", "https", url.getProtocol()); } + public static void assertResponseCodeOk(String url) throws IOException { + HttpURLConnection connection = (HttpURLConnection) urlFromString(url).openConnection(); + int responseCode = connection.getResponseCode(); + assertTrue("Url returned error code " + responseCode + ": " + url, responseCode < 400); + } + + + public static void assertNotEmpty(String stringToCheck) { assertNotEmpty(null, stringToCheck); } From 0ced6ae599fc04e0a76a78478e92cb7b0d2d4155 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 17 Aug 2019 11:28:29 +0200 Subject: [PATCH 07/16] Add base class for youtube stream extractor tests --- ...utubeStreamExtractorAgeRestrictedTest.java | 133 ------------------ .../YoutubeStreamExtractorBaseTest.java | 114 +++++++++++++++ ...utubeStreamExtractorControversialTest.java | 124 ---------------- .../YoutubeStreamExtractorDefaultTest.java | 94 +------------ 4 files changed, 119 insertions(+), 346 deletions(-) delete mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java delete mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java deleted file mode 100644 index 6a24ec5f2a..0000000000 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.schabi.newpipe.extractor.services.youtube.stream; - -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; -import org.schabi.newpipe.Downloader; -import org.schabi.newpipe.extractor.MediaFormat; -import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; -import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory; -import org.schabi.newpipe.extractor.stream.StreamExtractor; -import org.schabi.newpipe.extractor.stream.VideoStream; -import org.schabi.newpipe.extractor.utils.Localization; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.*; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; -import static org.schabi.newpipe.extractor.ServiceList.YouTube; - -/** - * Test for {@link YoutubeStreamLinkHandlerFactory} - */ -public class YoutubeStreamExtractorAgeRestrictedTest { - public static final String HTTPS = "https://"; - private static YoutubeStreamExtractor extractor; - - @BeforeClass - public static void setUp() throws Exception { - NewPipe.init(Downloader.getInstance(), new Localization("GB", "en")); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=MmBeUZqv1QA"); - extractor.fetchPage(); - } - - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", extractor.getTimeStamp() <= 0); - } - - @Test - public void testGetValidTimeStamp() throws IOException, ExtractionException { - StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); - assertEquals(extractor.getTimeStamp() + "", "174"); - } - - @Test - public void testGetAgeLimit() throws ParsingException { - assertEquals(18, extractor.getAgeLimit()); - } - - @Test - public void testGetName() throws ParsingException { - assertNotNull("name is null", extractor.getName()); - assertFalse("name is empty", extractor.getName().isEmpty()); - } - - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().isEmpty()); - } - - @Test - public void testGetUploaderName() throws ParsingException { - assertNotNull(extractor.getUploaderName()); - assertFalse(extractor.getUploaderName().isEmpty()); - } - - @Test - public void testGetLength() throws ParsingException { - assertEquals(1789, extractor.getLength()); - } - - @Test - public void testGetViews() throws ParsingException { - assertTrue(extractor.getViewCount() > 0); - } - - @Test - public void testGetUploadDate() throws ParsingException { - assertTrue(extractor.getUploadDate().length() > 0); - } - - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } - - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetAudioStreams() throws IOException, ExtractionException { - // audio streams are not always necessary - assertFalse(extractor.getAudioStreams().isEmpty()); - } - - @Test - public void testGetVideoStreams() throws IOException, ExtractionException { - List streams = new ArrayList<>(); - streams.addAll(extractor.getVideoStreams()); - streams.addAll(extractor.getVideoOnlyStreams()); - - assertTrue(Integer.toString(streams.size()),streams.size() > 0); - for (VideoStream s : streams) { - assertTrue(s.getUrl(), - s.getUrl().contains(HTTPS)); - assertTrue(s.resolution.length() > 0); - assertTrue(Integer.toString(s.getFormatId()), - 0 <= s.getFormatId() && s.getFormatId() <= 0x100); - } - } - - - @Test - public void testGetSubtitlesListDefault() throws IOException, ExtractionException { - // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null - assertTrue(extractor.getSubtitlesDefault().isEmpty()); - } - - @Test - public void testGetSubtitlesList() throws IOException, ExtractionException { - // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null - assertTrue(extractor.getSubtitles(MediaFormat.TTML).isEmpty()); - } -} diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java new file mode 100644 index 0000000000..dd29ead271 --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java @@ -0,0 +1,114 @@ +package org.schabi.newpipe.extractor.services.youtube.stream; + +import org.junit.Test; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; +import org.schabi.newpipe.extractor.stream.AudioStream; +import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector; +import org.schabi.newpipe.extractor.stream.StreamType; +import org.schabi.newpipe.extractor.stream.VideoStream; +import org.schabi.newpipe.extractor.utils.Utils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; +import static org.schabi.newpipe.extractor.ExtractorAsserts.*; + +public abstract class YoutubeStreamExtractorBaseTest { + public static YoutubeStreamExtractor extractor; + + @Test + public void testGetAgeLimit() throws ParsingException { + assertEquals(YoutubeStreamExtractor.NO_AGE_LIMIT, extractor.getAgeLimit()); + } + + @Test + public void testGetTitle() throws ParsingException { + assertFalse(extractor.getName().isEmpty()); + } + + @Test + public void testGetDescription() throws ParsingException { + assertNotNull(extractor.getDescription()); + assertFalse(extractor.getDescription().isEmpty()); + } + + @Test + public void testGetUploaderName() throws ParsingException { + assertNotNull(extractor.getUploaderName()); + assertFalse(extractor.getUploaderName().isEmpty()); + } + + @Test + public void testGetLength() throws ParsingException { + long length = extractor.getLength(); + assertTrue(String.valueOf(length), length > 0); + } + + @Test + public void testGetViewCount() throws ParsingException { + long count = extractor.getViewCount(); + assertTrue(Long.toString(count), count > 0); + } + + @Test + public void testGetUploadDate() throws ParsingException { + assertTrue(extractor.getUploadDate().length() > 0); + } + + @Test + public void testGetUploaderUrl() throws ParsingException { + String uploaderUrl = extractor.getUploaderUrl(); + assertTrue(uploaderUrl.startsWith("https://www.youtube.com/channel/")); + } + + @Test + public void testGetThumbnailUrl() throws ParsingException { + assertIsSecureUrl(extractor.getThumbnailUrl()); + } + + @Test + public void testGetUploaderAvatarUrl() throws ParsingException { + assertIsSecureUrl(extractor.getUploaderAvatarUrl()); + } + + @Test + public void testGetAudioStreams() throws IOException, ExtractionException { + for (AudioStream s : extractor.getAudioStreams()) { + assertIsSecureUrl(s.url); + assertResponseCodeOk(s.url); + } + } + + @Test + public void testGetVideoStreams() throws IOException, ExtractionException { + List streams = new ArrayList<>(); + streams.addAll(extractor.getVideoStreams()); + streams.addAll(extractor.getVideoOnlyStreams()); + + for (VideoStream s : streams) { + assertIsSecureUrl(s.url); + assertResponseCodeOk(s.url); + assertTrue(s.resolution.length() > 0); + assertTrue(Integer.toString(s.getFormatId()), + 0 <= s.getFormatId() && s.getFormatId() <= 0x100); + } + assertFalse(streams.isEmpty()); + } + + @Test + public void testStreamType() throws ParsingException { + assertTrue(extractor.getStreamType() == StreamType.VIDEO_STREAM); + } + + @Test + public void testGetRelatedVideos() throws ExtractionException, IOException { + StreamInfoItemsCollector relatedVideos = extractor.getRelatedStreams(); + Utils.printErrors(relatedVideos.getErrors()); + assertFalse(relatedVideos.getItems().isEmpty()); + assertTrue(relatedVideos.getErrors().isEmpty()); + } +} diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java deleted file mode 100644 index 261d521c16..0000000000 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.schabi.newpipe.extractor.services.youtube.stream; - -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; -import org.schabi.newpipe.Downloader; -import org.schabi.newpipe.extractor.MediaFormat; -import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.exceptions.ParsingException; -import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; -import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory; -import org.schabi.newpipe.extractor.stream.StreamExtractor; -import org.schabi.newpipe.extractor.stream.VideoStream; -import org.schabi.newpipe.extractor.utils.Localization; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.*; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; -import static org.schabi.newpipe.extractor.ServiceList.YouTube; - -/** - * Test for {@link YoutubeStreamLinkHandlerFactory} - */ -public class YoutubeStreamExtractorControversialTest { - private static YoutubeStreamExtractor extractor; - - @BeforeClass - public static void setUp() throws Exception { - NewPipe.init(Downloader.getInstance(), new Localization("GB", "en")); - extractor = (YoutubeStreamExtractor) YouTube - .getStreamExtractor("https://www.youtube.com/watch?v=T4XJQO3qol8"); - extractor.fetchPage(); - } - - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", extractor.getTimeStamp() <= 0); - } - - @Test - public void testGetValidTimeStamp() throws IOException, ExtractionException { - StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); - assertEquals(extractor.getTimeStamp() + "", "174"); - } - - @Test - @Ignore - public void testGetAgeLimit() throws ParsingException { - assertEquals(18, extractor.getAgeLimit()); - } - - @Test - public void testGetName() throws ParsingException { - assertNotNull("name is null", extractor.getName()); - assertFalse("name is empty", extractor.getName().isEmpty()); - } - - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); -// assertFalse(extractor.getDescription().isEmpty()); - } - - @Test - public void testGetUploaderName() throws ParsingException { - assertNotNull(extractor.getUploaderName()); - assertFalse(extractor.getUploaderName().isEmpty()); - } - - @Test - public void testGetLength() throws ParsingException { - assertEquals(219, extractor.getLength()); - } - - @Test - public void testGetViews() throws ParsingException { - assertTrue(extractor.getViewCount() > 0); - } - - @Test - public void testGetUploadDate() throws ParsingException { - assertTrue(extractor.getUploadDate().length() > 0); - } - - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } - - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetAudioStreams() throws IOException, ExtractionException { - // audio streams are not always necessary - assertFalse(extractor.getAudioStreams().isEmpty()); - } - - @Test - public void testGetVideoStreams() throws IOException, ExtractionException { - List streams = new ArrayList<>(); - streams.addAll(extractor.getVideoStreams()); - streams.addAll(extractor.getVideoOnlyStreams()); - assertTrue(streams.size() > 0); - } - - @Test - public void testGetSubtitlesListDefault() throws IOException, ExtractionException { - // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null - assertFalse(extractor.getSubtitlesDefault().isEmpty()); - } - - @Test - public void testGetSubtitlesList() throws IOException, ExtractionException { - // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null - assertFalse(extractor.getSubtitles(MediaFormat.TTML).isEmpty()); - } -} diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java index a0e5050ab7..d153f9fee6 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java @@ -11,13 +11,11 @@ import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; import org.schabi.newpipe.extractor.stream.*; import org.schabi.newpipe.extractor.utils.Localization; -import org.schabi.newpipe.extractor.utils.Utils; import java.io.IOException; import java.util.List; import static org.junit.Assert.*; -import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; import static org.schabi.newpipe.extractor.ServiceList.YouTube; /* @@ -48,9 +46,7 @@ public class YoutubeStreamExtractorDefaultTest { /** * Test for {@link StreamExtractor} */ - public static class AdeleHello { - private static YoutubeStreamExtractor extractor; - + public static class AdeleHello extends YoutubeStreamExtractorBaseTest { @BeforeClass public static void setUp() throws Exception { NewPipe.init(Downloader.getInstance(), new Localization("GB", "en")); @@ -71,17 +67,6 @@ public void testGetValidTimeStamp() throws ExtractionException { assertEquals(extractor.getTimeStamp() + "", "174"); } - @Test - public void testGetTitle() throws ParsingException { - assertFalse(extractor.getName().isEmpty()); - } - - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().isEmpty()); - } - @Test public void testGetFullLinksInDescription() throws ParsingException { assertTrue(extractor.getDescription().contains("http://adele.com")); @@ -89,63 +74,18 @@ public void testGetFullLinksInDescription() throws ParsingException { } @Test - public void testGetUploaderName() throws ParsingException { - assertNotNull(extractor.getUploaderName()); - assertFalse(extractor.getUploaderName().isEmpty()); - } - - - @Test + @Override public void testGetLength() throws ParsingException { assertEquals(366, extractor.getLength()); } @Test + @Override public void testGetViewCount() throws ParsingException { Long count = extractor.getViewCount(); assertTrue(Long.toString(count), count >= /* specific to that video */ 1220025784); } - @Test - public void testGetUploadDate() throws ParsingException { - assertTrue(extractor.getUploadDate().length() > 0); - } - - @Test - public void testGetUploaderUrl() throws ParsingException { - assertEquals("https://www.youtube.com/channel/UCsRM0YB_dabtEPGPTKo-gcw", extractor.getUploaderUrl()); - } - - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } - - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetAudioStreams() throws IOException, ExtractionException { - assertFalse(extractor.getAudioStreams().isEmpty()); - } - - @Test - public void testGetVideoStreams() throws IOException, ExtractionException { - for (VideoStream s : extractor.getVideoStreams()) { - assertIsSecureUrl(s.url); - assertTrue(s.resolution.length() > 0); - assertTrue(Integer.toString(s.getFormatId()), - 0 <= s.getFormatId() && s.getFormatId() <= 0x100); - } - } - - @Test - public void testStreamType() throws ParsingException { - assertTrue(extractor.getStreamType() == StreamType.VIDEO_STREAM); - } - @Test public void testGetDashMpd() throws ParsingException { // we dont expect this particular video to have a DASH file. For this purpouse we use a different test class. @@ -153,14 +93,6 @@ public void testGetDashMpd() throws ParsingException { extractor.getDashMpdUrl() != null && extractor.getDashMpdUrl().isEmpty()); } - @Test - public void testGetRelatedVideos() throws ExtractionException, IOException { - StreamInfoItemsCollector relatedVideos = extractor.getRelatedStreams(); - Utils.printErrors(relatedVideos.getErrors()); - assertFalse(relatedVideos.getItems().isEmpty()); - assertTrue(relatedVideos.getErrors().isEmpty()); - } - @Test public void testGetSubtitlesListDefault() throws IOException, ExtractionException { // Video (/view?v=YQHsXMglC9A) set in the setUp() method has no captions => null @@ -174,9 +106,7 @@ public void testGetSubtitlesList() throws IOException, ExtractionException { } } - public static class DescriptionTestPewdiepie { - private static YoutubeStreamExtractor extractor; - + public static class DescriptionTestPewdiepie extends YoutubeStreamExtractorBaseTest { @BeforeClass public static void setUp() throws Exception { NewPipe.init(Downloader.getInstance(), new Localization("GB", "en")); @@ -185,12 +115,6 @@ public static void setUp() throws Exception { extractor.fetchPage(); } - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().isEmpty()); - } - @Test public void testGetFullLinksInDescription() throws ParsingException { assertTrue(extractor.getDescription().contains("https://www.reddit.com/r/PewdiepieSubmissions/")); @@ -203,9 +127,7 @@ public void testGetFullLinksInDescription() throws ParsingException { } } - public static class DescriptionTestUnboxing { - private static YoutubeStreamExtractor extractor; - + public static class DescriptionTestUnboxing extends YoutubeStreamExtractorBaseTest { @BeforeClass public static void setUp() throws Exception { NewPipe.init(Downloader.getInstance(), new Localization("GB", "en")); @@ -214,12 +136,6 @@ public static void setUp() throws Exception { extractor.fetchPage(); } - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().isEmpty()); - } - @Test public void testGetFullLinksInDescription() throws ParsingException { assertTrue(extractor.getDescription().contains("https://www.youtube.com/watch?v=X7FLCHVXpsA&list=PL7u4lWXQ3wfI_7PgX0C-VTiwLeu0S4v34")); From 8af85fe936e19d57eb9bc78232603e718ffd7670 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 3 Oct 2019 20:24:02 +0200 Subject: [PATCH 08/16] Simplify code --- .../services/youtube/search/YoutubeSearchCountTest.java | 2 +- .../services/youtube/stream/YoutubeStreamExtractorBaseTest.java | 2 +- .../youtube/stream/YoutubeStreamExtractorDefaultTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/search/YoutubeSearchCountTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/search/YoutubeSearchCountTest.java index 35b138e424..7eb353f032 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/search/YoutubeSearchCountTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/search/YoutubeSearchCountTest.java @@ -30,7 +30,7 @@ public static void setUpClass() throws Exception { @Test public void testViewCount() { ChannelInfoItem ci = (ChannelInfoItem) itemsPage.getItems().get(0); - assertTrue("Count does not fit: " + Long.toString(ci.getSubscriberCount()), + assertTrue("Count does not fit: " + ci.getSubscriberCount(), 69043316 < ci.getSubscriberCount() && ci.getSubscriberCount() < 103043316); } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java index dd29ead271..622aaf33d2 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java @@ -101,7 +101,7 @@ public void testGetVideoStreams() throws IOException, ExtractionException { @Test public void testStreamType() throws ParsingException { - assertTrue(extractor.getStreamType() == StreamType.VIDEO_STREAM); + assertSame(extractor.getStreamType(), StreamType.VIDEO_STREAM); } @Test diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java index d153f9fee6..1259067d61 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java @@ -82,7 +82,7 @@ public void testGetLength() throws ParsingException { @Test @Override public void testGetViewCount() throws ParsingException { - Long count = extractor.getViewCount(); + long count = extractor.getViewCount(); assertTrue(Long.toString(count), count >= /* specific to that video */ 1220025784); } From aea44ad9a49283860671fd6f3c4e56bc7671e437 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sun, 3 Nov 2019 14:37:45 +0100 Subject: [PATCH 09/16] Subclass BlockJUnit4ClassRunner in NewPipeTestRunner This removes much of the code that was used to get and invoke methods. Now the class Runner is also able to run individual tests. --- .../org/schabi/newpipe/NewPipeTestRunner.java | 305 +++++------------- 1 file changed, 74 insertions(+), 231 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java index b343fc4c71..be0c8c44a5 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java @@ -1,74 +1,52 @@ package org.schabi.newpipe; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Ignore; -import org.junit.Test; +import org.junit.internal.AssumptionViolatedException; import org.junit.runner.Description; -import org.junit.runner.Runner; import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; -import org.junit.runners.model.TestTimedOutException; +import org.junit.runners.model.Statement; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -public class NewPipeTestRunner extends Runner { - - private class TestException extends Exception { - TestException(Throwable throwable) { - super(throwable); - } - } +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +public class NewPipeTestRunner extends BlockJUnit4ClassRunner { private class MethodResultCollector { - boolean ignoredByUser; - String ignoredByUserReason; - String methodName; - Throwable thrownException; + @Nullable String ignoredByUserReason; + Description description; - MethodResultCollector(Method method, Object testClassInstance) throws IllegalAccessException, ExecutionException, InterruptedException { - ignoredByUser = method.isAnnotationPresent(Ignore.class); - methodName = method.getName(); - thrownException = null; + @Nullable AssumptionViolatedException failedAssumption; + @Nullable Throwable thrownException; - if (ignoredByUser) { - ignoredByUserReason = method.getAnnotation(Ignore.class).value(); - return; - } + MethodResultCollector(Description description, @Nonnull String ignoredByUserReason) { + this.description = description; + this.ignoredByUserReason = ignoredByUserReason; + } - Test testAnnotation = method.getAnnotation(Test.class); - Class expectedThrowable = testAnnotation.expected(); - long timeout = testAnnotation.timeout(); + MethodResultCollector(Description description, Statement statement) { + this.description = description; + this.ignoredByUserReason = null; // not ignored try { - invokeAllMethods(beforeMethods, testClassInstance); - invokeCheckingTimeAndExceptions(method, testClassInstance, timeout, expectedThrowable); - invokeAllMethods(afterMethods, testClassInstance); - } catch (InvocationTargetException e) { - thrownException = e.getCause(); - } catch (TestException e) { - thrownException = e.getCause(); + statement.evaluate(); + } catch (AssumptionViolatedException e) { + failedAssumption = e; + } catch (Throwable e) { + thrownException = e; } } boolean isIgnoredByUser() { - return ignoredByUser; + return ignoredByUserReason != null; } boolean isSuccessful() { @@ -77,192 +55,51 @@ boolean isSuccessful() { void showResults(RunNotifier notifier, boolean ignoreAnyError) { - Description methodDescription = Description.createTestDescription(testClass, methodName); - - if (ignoredByUser) { - notifier.fireTestIgnored(methodDescription); - if (ignoredByUserReason.isEmpty()) { - System.out.println(methodName + "() ignored because of @Ignore"); - } else { - System.out.println(methodName + "() ignored because of @Ignore: " + ignoredByUserReason); - } - - } else { - if (thrownException == null) { - notifier.fireTestStarted(methodDescription); - notifier.fireTestFinished(methodDescription); + if (ignoredByUserReason == null) { // not ignored + if (thrownException == null && failedAssumption == null) { + notifier.fireTestStarted(description); + notifier.fireTestFinished(description); } else if (thrownException instanceof ReCaptchaException) { - notifier.fireTestIgnored(methodDescription); - System.out.println(methodName + "() ignored since it threw a ReCaptchaException"); + notifier.fireTestIgnored(description); + System.out.println(description.getMethodName() + "() ignored since it threw a ReCaptchaException"); thrownException.printStackTrace(System.out); } else if (ignoreAnyError) { - notifier.fireTestIgnored(methodDescription); - System.out.println(methodName + "() ignored since the whole class " + testClass.getName() + + notifier.fireTestIgnored(description); + System.out.println(description.getMethodName() + "() ignored since the whole class " + testClass.getName() + " has more than " + (int)(failRatioTriggeringIgnore*100) + "% of failed tests"); thrownException.printStackTrace(System.out); } else { - notifier.fireTestStarted(methodDescription); - notifier.fireTestFailure(new Failure(methodDescription, thrownException)); - notifier.fireTestFinished(methodDescription); - + notifier.fireTestStarted(description); + if (thrownException == null) { + notifier.fireTestAssumptionFailed(new Failure(description, failedAssumption)); + } else { + notifier.fireTestFailure(new Failure(description, thrownException)); + } + notifier.fireTestFinished(description); } + } else { + notifier.fireTestIgnored(description); + System.out.println(description.getMethodName() + "() ignored because of @Ignore" + + (ignoredByUserReason.isEmpty() ? "" : ": " + ignoredByUserReason)); } } } - private Class testClass; + private final Class testClass; private float failRatioTriggeringIgnore; - private final ArrayList testMethods, - beforeMethods, afterMethods, - beforeClassMethods, afterClassMethods; + private List results; public NewPipeTestRunner(Class testClass) throws InitializationError { + super(testClass); this.testClass = testClass; obtainRunnerOptions(); - - testMethods = new ArrayList<>(); - beforeMethods = new ArrayList<>(); - afterMethods = new ArrayList<>(); - beforeClassMethods = new ArrayList<>(); - afterClassMethods = new ArrayList<>(); - - for (Method method : testClass.getDeclaredMethods()) { - if (method.isAnnotationPresent(Test.class)) { - validatePublicVoidNoArg(method, false); - testMethods.add(method); - - } else if (method.isAnnotationPresent(Before.class)) { - validatePublicVoidNoArg(method, false); - beforeMethods.add(method); - - } else if (method.isAnnotationPresent(After.class)) { - validatePublicVoidNoArg(method, false); - afterMethods.add(method); - - } else if (method.isAnnotationPresent(BeforeClass.class)) { - validatePublicVoidNoArg(method, true); - beforeClassMethods.add(method); - - } else if (method.isAnnotationPresent(AfterClass.class)) { - validatePublicVoidNoArg(method, true); - afterClassMethods.add(method); - - } - } - } - - - @Override - public Description getDescription() { - return Description.createTestDescription(testClass, "NewPipe custom runner"); - } - - - private static void validatePublicVoidNoArg(Method method, boolean shouldBeStatic) throws InitializationError { - List errors = new ArrayList<>(); - - if (method.getParameterTypes().length != 0) { - errors.add(new Exception("Method " + method.getName() + " should have no parameters")); - } - if (Modifier.isStatic(method.getModifiers()) != shouldBeStatic) { - String state = shouldBeStatic ? "should" : "should not"; - errors.add(new Exception("Method " + method.getName() + "() " + state + " be static")); - } - if (!Modifier.isPublic(method.getModifiers())) { - errors.add(new Exception("Method " + method.getName() + "() should be public")); - } - if (method.getReturnType() != Void.TYPE) { - errors.add(new Exception("Method " + method.getName() + "() should be void")); - } - - if (!errors.isEmpty()) { - throw new InitializationError(errors); - } - } - - private static void invokeAllMethods(List methods, Object testClassInstance) throws InvocationTargetException, IllegalAccessException { - for (Method method : methods) { - method.invoke(testClassInstance); - } - } - - class MethodRunnableCollectingExceptions implements Runnable { - InvocationTargetException collectedInvocationTargetException; - IllegalAccessException collectedIllegalAccessException; - Method method; - Object testClassInstance; - - MethodRunnableCollectingExceptions(Method method, Object testClassInstance) { - this.method = method; - this.testClassInstance = testClassInstance; - } - - @Override - public final void run() { - try { - method.invoke(testClassInstance); - } catch (InvocationTargetException e) { - collectedInvocationTargetException = e; - } catch (IllegalAccessException e) { - collectedIllegalAccessException = e; - } - } - - void throwCollectedThrowableIfPresent() throws InvocationTargetException, IllegalAccessException { - if (collectedInvocationTargetException != null) { - throw collectedInvocationTargetException; - } else if (collectedIllegalAccessException != null) { - throw collectedIllegalAccessException; - } - } - } - - private void invokeWithTimeout(final Method method, final Object testClassInstance, long timeout) throws InvocationTargetException, IllegalAccessException, TestException, InterruptedException, ExecutionException { - if (timeout > 0) { - final ExecutorService executorService = Executors.newSingleThreadExecutor(); - MethodRunnableCollectingExceptions runnable = new MethodRunnableCollectingExceptions(method, testClassInstance); - - try { - final Future f = (Future) executorService.submit(runnable); - f.get(timeout, TimeUnit.MILLISECONDS); - runnable.throwCollectedThrowableIfPresent(); - } catch (final TimeoutException e) { - throw new TestException(new TestTimedOutException(timeout, TimeUnit.MILLISECONDS)); - } finally { - executorService.shutdown(); - } - } else { - method.invoke(testClassInstance); - } } - private void invokeCheckingTimeAndExceptions(Method method, Object testClassInstance, long timeout, Class expectedThrowable) throws InvocationTargetException, IllegalAccessException, TestException, ExecutionException, InterruptedException { - boolean complete = false; - try { - invokeWithTimeout(method, testClassInstance, timeout); - complete = true; - } catch (InvocationTargetException e) { - if (expectedThrowable.equals(Test.None.class)) { - throw e; - } else if (!expectedThrowable.isInstance(e.getCause())) { - String message = "Unexpected exception, expected <" + expectedThrowable.getName() + - "> but was <" + e.getCause().getClass().getName() + ">"; - throw new TestException(new Exception(message, e)); - } - } - - if (complete && !expectedThrowable.equals(Test.None.class)) { - String message = "Expected exception <" + expectedThrowable.getName() + ">"; - throw new TestException(new Exception(message)); - } - } - - private void obtainRunnerOptions() { if (testClass.isAnnotationPresent(NewPipeTestRunnerOptions.class)) { NewPipeTestRunnerOptions options = (NewPipeTestRunnerOptions) testClass.getAnnotation(NewPipeTestRunnerOptions.class); @@ -276,33 +113,39 @@ private void obtainRunnerOptions() { @Override public void run(RunNotifier notifier) { - try { - Object testClassInstance = testClass.newInstance(); - invokeAllMethods(beforeClassMethods, testClassInstance); - - List savedResults = new ArrayList<>(); - for (Method testMethod : testMethods) { - savedResults.add(new MethodResultCollector(testMethod, testClassInstance)); - } - - int nrSuccessful = 0, nrNotIgnoredByUser = 0; - for (MethodResultCollector savedResult : savedResults) { - if (!savedResult.isIgnoredByUser()) { - ++nrNotIgnoredByUser; - if (savedResult.isSuccessful()) { - ++nrSuccessful; - } + results = new ArrayList<>(); + super.run(notifier); + + int nrSuccessful = 0, nrNotIgnoredByUser = 0; + for (MethodResultCollector result : results) { + if (!result.isIgnoredByUser()) { + ++nrNotIgnoredByUser; + if (result.isSuccessful()) { + ++nrSuccessful; } } + } - for (MethodResultCollector savedResult : savedResults) { - savedResult.showResults(notifier, (float)(nrNotIgnoredByUser - nrSuccessful) / nrNotIgnoredByUser > failRatioTriggeringIgnore); - } + boolean ignoreAnyError; + if (nrNotIgnoredByUser <= 1) { + ignoreAnyError = false; + } else { + ignoreAnyError = ((float)(nrNotIgnoredByUser - nrSuccessful) / nrNotIgnoredByUser) > failRatioTriggeringIgnore; + } - invokeAllMethods(afterClassMethods, testClassInstance); - } catch (Exception e) { - throw new RuntimeException(e); + for (MethodResultCollector result : results) { + result.showResults(notifier, ignoreAnyError); } } + @Override + protected void runChild(FrameworkMethod method, RunNotifier notifier) { + Description description = describeChild(method); + if (isIgnored(method)) { + results.add(new MethodResultCollector(description, method.getAnnotation(Ignore.class).value())); + } else { + Statement statement = methodBlock(method); + results.add(new MethodResultCollector(description, statement)); + } + } } From cdc6c21d0e4965bcccff0a381cb8e86f98a0c33e Mon Sep 17 00:00:00 2001 From: Stypox Date: Sun, 3 Nov 2019 15:43:00 +0100 Subject: [PATCH 10/16] Remove failRatioTriggeringIgnore It is too risky to silently ignore tests that actually failed. The fact that many tests in a class fail indicates that there is a problem in the set-up methods (`@BeforeClass`). We can't assume that the problem in set-up methods is a network error, since it could as well be a programming error. Also `ReCaptchaException`s are now considered a violated assumption (same as AssumptionViolatedException), since that's what they are. This allows to call `fireTestStarted` before invoking the tested method, thus correctly mesuring the elapsed time. --- .../org/schabi/newpipe/NewPipeTestRunner.java | 140 +++--------------- .../newpipe/NewPipeTestRunnerOptions.java | 14 +- 2 files changed, 23 insertions(+), 131 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java index be0c8c44a5..2dc616e49e 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java @@ -11,141 +11,45 @@ import org.junit.runners.model.Statement; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - public class NewPipeTestRunner extends BlockJUnit4ClassRunner { - - private class MethodResultCollector { - @Nullable String ignoredByUserReason; - Description description; - - @Nullable AssumptionViolatedException failedAssumption; - @Nullable Throwable thrownException; - - MethodResultCollector(Description description, @Nonnull String ignoredByUserReason) { - this.description = description; - this.ignoredByUserReason = ignoredByUserReason; - } - - MethodResultCollector(Description description, Statement statement) { - this.description = description; - this.ignoredByUserReason = null; // not ignored - - try { - statement.evaluate(); - } catch (AssumptionViolatedException e) { - failedAssumption = e; - } catch (Throwable e) { - thrownException = e; - } - } - - - boolean isIgnoredByUser() { - return ignoredByUserReason != null; - } - - boolean isSuccessful() { - return thrownException == null; - } - - - void showResults(RunNotifier notifier, boolean ignoreAnyError) { - if (ignoredByUserReason == null) { // not ignored - if (thrownException == null && failedAssumption == null) { - notifier.fireTestStarted(description); - notifier.fireTestFinished(description); - - } else if (thrownException instanceof ReCaptchaException) { - notifier.fireTestIgnored(description); - System.out.println(description.getMethodName() + "() ignored since it threw a ReCaptchaException"); - thrownException.printStackTrace(System.out); - - } else if (ignoreAnyError) { - notifier.fireTestIgnored(description); - System.out.println(description.getMethodName() + "() ignored since the whole class " + testClass.getName() + - " has more than " + (int)(failRatioTriggeringIgnore*100) + "% of failed tests"); - thrownException.printStackTrace(System.out); - - } else { - notifier.fireTestStarted(description); - if (thrownException == null) { - notifier.fireTestAssumptionFailed(new Failure(description, failedAssumption)); - } else { - notifier.fireTestFailure(new Failure(description, thrownException)); - } - notifier.fireTestFinished(description); - } - } else { - notifier.fireTestIgnored(description); - System.out.println(description.getMethodName() + "() ignored because of @Ignore" + - (ignoredByUserReason.isEmpty() ? "" : ": " + ignoredByUserReason)); - } - } - - } - - - private final Class testClass; - private float failRatioTriggeringIgnore; - private List results; - public NewPipeTestRunner(Class testClass) throws InitializationError { super(testClass); - this.testClass = testClass; - obtainRunnerOptions(); - } - private void obtainRunnerOptions() { if (testClass.isAnnotationPresent(NewPipeTestRunnerOptions.class)) { NewPipeTestRunnerOptions options = (NewPipeTestRunnerOptions) testClass.getAnnotation(NewPipeTestRunnerOptions.class); - - failRatioTriggeringIgnore = options.failRatioTriggeringIgnore(); } else { throw new IllegalArgumentException("Test classes running with " + NewPipeTestRunner.class.getName() + " should also have @NewPipeTestRunnerOptions"); } } - - @Override - public void run(RunNotifier notifier) { - results = new ArrayList<>(); - super.run(notifier); - - int nrSuccessful = 0, nrNotIgnoredByUser = 0; - for (MethodResultCollector result : results) { - if (!result.isIgnoredByUser()) { - ++nrNotIgnoredByUser; - if (result.isSuccessful()) { - ++nrSuccessful; - } - } - } - - boolean ignoreAnyError; - if (nrNotIgnoredByUser <= 1) { - ignoreAnyError = false; - } else { - ignoreAnyError = ((float)(nrNotIgnoredByUser - nrSuccessful) / nrNotIgnoredByUser) > failRatioTriggeringIgnore; - } - - for (MethodResultCollector result : results) { - result.showResults(notifier, ignoreAnyError); - } - } - @Override protected void runChild(FrameworkMethod method, RunNotifier notifier) { Description description = describeChild(method); + if (isIgnored(method)) { - results.add(new MethodResultCollector(description, method.getAnnotation(Ignore.class).value())); + notifier.fireTestIgnored(description); + + String ignoreReason = method.getAnnotation(Ignore.class).value(); + System.out.println(method.getName() + "() ignored because of @Ignore" + + (ignoreReason.isEmpty() ? "" : ": " + ignoreReason)); } else { Statement statement = methodBlock(method); - results.add(new MethodResultCollector(description, statement)); + + notifier.fireTestStarted(description); + try { + statement.evaluate(); + } catch (AssumptionViolatedException | ReCaptchaException e) { + notifier.fireTestAssumptionFailed(new Failure(description, e)); + + if (e instanceof ReCaptchaException) { + System.out.println(method.getName() + "() ignored since it threw a ReCaptchaException"); + } + + } catch (Throwable e) { + notifier.fireTestFailure(new Failure(description, e)); + } finally { + notifier.fireTestFinished(description); + } } } } diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java index c582e10b8e..4431d380b4 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java @@ -5,17 +5,5 @@ @Retention(RetentionPolicy.RUNTIME) public @interface NewPipeTestRunnerOptions { - /** - * The ratio between the number of failed tests and the total number - * of tests that have not been {@link org.junit.Ignore}d by the user. - * Above this ratio the Runner will ignore all failing tests, since - * there probably is a problem with YouTube blocking robots. A warning - * along with a stack trace are displayed anyway. - *

- * A value >= 1.0f means the same as "never ignore any failed test" - * A value <= 0.0 means the same as "ignore all failed tests" - * - * @return the failedTests/notIgnoredTests ratio above which all failing tests are ignored - */ - float failRatioTriggeringIgnore() default 1.1f; + } From ba93740599e685a14f46f994329fc72c46e5a863 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sun, 3 Nov 2019 20:17:13 +0100 Subject: [PATCH 11/16] Add delays before running the class or each method in custom Runner This will prevent overloads on services' servers. --- .../org/schabi/newpipe/NewPipeTestRunner.java | 26 +++++++++++++++++-- .../newpipe/NewPipeTestRunnerOptions.java | 12 +++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java index 2dc616e49e..3be15d0681 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java @@ -11,17 +11,37 @@ import org.junit.runners.model.Statement; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; +import java.util.concurrent.TimeUnit; + public class NewPipeTestRunner extends BlockJUnit4ClassRunner { + private final NewPipeTestRunnerOptions options; + public NewPipeTestRunner(Class testClass) throws InitializationError { super(testClass); if (testClass.isAnnotationPresent(NewPipeTestRunnerOptions.class)) { - NewPipeTestRunnerOptions options = (NewPipeTestRunnerOptions) testClass.getAnnotation(NewPipeTestRunnerOptions.class); + options = (NewPipeTestRunnerOptions) testClass.getAnnotation(NewPipeTestRunnerOptions.class); } else { throw new IllegalArgumentException("Test classes running with " + NewPipeTestRunner.class.getName() + " should also have @NewPipeTestRunnerOptions"); } } + public void sleep(int milliseconds) { + if (milliseconds > 0) { + try { + TimeUnit.MILLISECONDS.sleep(milliseconds); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public void run(RunNotifier notifier) { + sleep(options.classDelayMs()); // @see NewPipeTestRunnerOptions.classDelayMs + super.run(notifier); + } + @Override protected void runChild(FrameworkMethod method, RunNotifier notifier) { Description description = describeChild(method); @@ -32,10 +52,12 @@ protected void runChild(FrameworkMethod method, RunNotifier notifier) { String ignoreReason = method.getAnnotation(Ignore.class).value(); System.out.println(method.getName() + "() ignored because of @Ignore" + (ignoreReason.isEmpty() ? "" : ": " + ignoreReason)); + } else { + sleep(options.methodDelayMs()); // @see NewPipeTestRunnerOptions.methodDelayMs Statement statement = methodBlock(method); - notifier.fireTestStarted(description); + try { statement.evaluate(); } catch (AssumptionViolatedException | ReCaptchaException e) { diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java index 4431d380b4..179d7c89cc 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java @@ -5,5 +5,17 @@ @Retention(RetentionPolicy.RUNTIME) public @interface NewPipeTestRunnerOptions { + /** + * This tells the Runner to wait some time before running + * the tests in the annotated class. + * @return milliseconds to sleep before testing the class + */ + int classDelayMs() default 0; + /** + * This tells the Runner to wait some time before invoking + * each test method in the annotated class. + * @return milliseconds to sleep before invoking each test method + */ + int methodDelayMs() default 0; } From dd608a8bfd99a40161c4a5eefae72e8ce802c80e Mon Sep 17 00:00:00 2001 From: Stypox Date: Sun, 3 Nov 2019 20:49:36 +0100 Subject: [PATCH 12/16] Validate options in custom Runner --- .../org/schabi/newpipe/NewPipeTestRunner.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java index 3be15d0681..950d06c632 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java @@ -21,12 +21,27 @@ public NewPipeTestRunner(Class testClass) throws InitializationError { if (testClass.isAnnotationPresent(NewPipeTestRunnerOptions.class)) { options = (NewPipeTestRunnerOptions) testClass.getAnnotation(NewPipeTestRunnerOptions.class); + validateOptions(testClass); } else { - throw new IllegalArgumentException("Test classes running with " + NewPipeTestRunner.class.getName() + " should also have @NewPipeTestRunnerOptions"); + throw new InitializationError("Test class " + testClass.getCanonicalName() + + " running with " + NewPipeTestRunner.class.getSimpleName() + " should have the @" + + NewPipeTestRunnerOptions.class.getSimpleName() + " annotation"); } } - public void sleep(int milliseconds) { + private void validateOptions(Class testClass) throws InitializationError { + if (options.classDelayMs() < 0) { + throw new InitializationError("classDelayMs value should not be negative in annotation @" + + NewPipeTestRunnerOptions.class.getSimpleName() + " in class " + testClass.getCanonicalName()); + } + if (options.methodDelayMs() < 0) { + throw new InitializationError("methodDelayMs value should not be negative in annotation @" + + NewPipeTestRunnerOptions.class.getSimpleName() + " in class " + testClass.getCanonicalName()); + } + } + + + private void sleep(int milliseconds) { if (milliseconds > 0) { try { TimeUnit.MILLISECONDS.sleep(milliseconds); From a2e021929b071f55e4dace6d53f554b94a27b338 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sun, 3 Nov 2019 21:17:14 +0100 Subject: [PATCH 13/16] Retry failing tests in custom Runner --- .../org/schabi/newpipe/NewPipeTestRunner.java | 42 +++++++++++++++---- .../newpipe/NewPipeTestRunnerOptions.java | 19 +++++++-- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java index 950d06c632..fd98fc1eca 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunner.java @@ -9,13 +9,17 @@ import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; -import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; public class NewPipeTestRunner extends BlockJUnit4ClassRunner { private final NewPipeTestRunnerOptions options; + private List methodsNotFailing; + private int currentRetry; + public NewPipeTestRunner(Class testClass) throws InitializationError { super(testClass); @@ -38,6 +42,10 @@ private void validateOptions(Class testClass) throws InitializationError { throw new InitializationError("methodDelayMs value should not be negative in annotation @" + NewPipeTestRunnerOptions.class.getSimpleName() + " in class " + testClass.getCanonicalName()); } + if (options.retry() < 1) { + throw new InitializationError("retry value should be bigger than 0 in annotation @" + + NewPipeTestRunnerOptions.class.getSimpleName() + " in class " + testClass.getCanonicalName()); + } } @@ -54,15 +62,24 @@ private void sleep(int milliseconds) { @Override public void run(RunNotifier notifier) { sleep(options.classDelayMs()); // @see NewPipeTestRunnerOptions.classDelayMs - super.run(notifier); + + methodsNotFailing = new ArrayList<>(); + for (currentRetry = 1; currentRetry <= options.retry(); ++currentRetry) { + if (getChildren().size() == methodsNotFailing.size()) { + break; + } + super.run(notifier); + } } @Override protected void runChild(FrameworkMethod method, RunNotifier notifier) { + if (isMethodAlreadyNotFailing(method)) return; Description description = describeChild(method); if (isIgnored(method)) { notifier.fireTestIgnored(description); + markMethodAsNotFailing(method); String ignoreReason = method.getAnnotation(Ignore.class).value(); System.out.println(method.getName() + "() ignored because of @Ignore" + @@ -75,18 +92,27 @@ protected void runChild(FrameworkMethod method, RunNotifier notifier) { try { statement.evaluate(); - } catch (AssumptionViolatedException | ReCaptchaException e) { - notifier.fireTestAssumptionFailed(new Failure(description, e)); + markMethodAsNotFailing(method); - if (e instanceof ReCaptchaException) { - System.out.println(method.getName() + "() ignored since it threw a ReCaptchaException"); + } catch (Throwable e) { + if (currentRetry < options.retry() || e instanceof AssumptionViolatedException) { + notifier.fireTestAssumptionFailed(new Failure(description, e)); + } else { + notifier.fireTestFailure(new Failure(description, e)); // test is not going to be retried anymore } - } catch (Throwable e) { - notifier.fireTestFailure(new Failure(description, e)); } finally { notifier.fireTestFinished(description); } } } + + + private void markMethodAsNotFailing(FrameworkMethod method) { + methodsNotFailing.add(method.getName()); + } + + private boolean isMethodAlreadyNotFailing(FrameworkMethod method) { + return methodsNotFailing.contains(method.getName()); + } } diff --git a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java index 179d7c89cc..95dab0e783 100644 --- a/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java +++ b/extractor/src/test/java/org/schabi/newpipe/NewPipeTestRunnerOptions.java @@ -6,16 +6,27 @@ @Retention(RetentionPolicy.RUNTIME) public @interface NewPipeTestRunnerOptions { /** - * This tells the Runner to wait some time before running - * the tests in the annotated class. + * This tells the Runner to wait the specified time before + * running the tests in the annotated class. * @return milliseconds to sleep before testing the class */ int classDelayMs() default 0; /** - * This tells the Runner to wait some time before invoking - * each test method in the annotated class. + * This tells the Runner to wait the specified time before + * invoking each test method in the annotated class. * @return milliseconds to sleep before invoking each test method */ int methodDelayMs() default 0; + + /** + * This tells the Runner to retry at most the specified number of + * times running the tests in the annotated class. As soon as the + * maximum number of retries is hit or all test methods succeed, + * the Runner completes, respectively with the last errors or + * with success. + * @return the number of times the class should be tested before + * declaring one of its test methods as failed. + */ + int retry() default 1; } From 69a59a125c299cc1c6714d7db4c90b99304960a6 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sun, 3 Nov 2019 21:36:09 +0100 Subject: [PATCH 14/16] Readd StreamExtractor tests accidentally deleted while rebasing --- ...utubeStreamExtractorAgeRestrictedTest.java | 73 ++++++++++++++++++ .../YoutubeStreamExtractorBaseTest.java | 4 +- ...utubeStreamExtractorControversialTest.java | 74 +++++++++++++++++++ 3 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java new file mode 100644 index 0000000000..7efcfaf63f --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java @@ -0,0 +1,73 @@ +package org.schabi.newpipe.extractor.services.youtube.stream; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.schabi.newpipe.Downloader; +import org.schabi.newpipe.extractor.MediaFormat; +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; +import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory; +import org.schabi.newpipe.extractor.stream.StreamExtractor; +import org.schabi.newpipe.extractor.utils.Localization; + +import java.io.IOException; + +import static org.junit.Assert.*; +import static org.schabi.newpipe.extractor.ServiceList.YouTube; + +/** + * Test for {@link YoutubeStreamLinkHandlerFactory} + */ +public class YoutubeStreamExtractorAgeRestrictedTest extends YoutubeStreamExtractorBaseTest { + + @BeforeClass + public static void setUp() throws Exception { + NewPipe.init(Downloader.getInstance(), new Localization("GB", "en")); + extractor = (YoutubeStreamExtractor) YouTube + .getStreamExtractor("https://www.youtube.com/watch?v=MmBeUZqv1QA"); + extractor.fetchPage(); + } + + @Test + public void testGetInvalidTimeStamp() throws ParsingException { + assertTrue(extractor.getTimeStamp() + "", extractor.getTimeStamp() <= 0); + } + + @Test + public void testGetValidTimeStamp() throws IOException, ExtractionException { + StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); + assertEquals(extractor.getTimeStamp() + "", "174"); + } + + @Test + public void testGetAgeLimit() throws ParsingException { + assertEquals(18, extractor.getAgeLimit()); + } + + @Test + public void testGetLength() throws ParsingException { + assertEquals(1789, extractor.getLength()); + } + + @Test + public void testGetAudioStreams() throws IOException, ExtractionException { + super.testGetAudioStreams(); + // audio streams are not always necessary + assertFalse(extractor.getAudioStreams().isEmpty()); + } + + + @Test + public void testGetSubtitlesListDefault() throws IOException, ExtractionException { + // Video (/view?v=MmBeUZqv1QA) set in the setUp() method has no captions => null + assertTrue(extractor.getSubtitlesDefault().isEmpty()); + } + + @Test + public void testGetSubtitlesList() throws IOException, ExtractionException { + // Video (/view?v=MmBeUZqv1QA) set in the setUp() method has no captions => null + assertTrue(extractor.getSubtitles(MediaFormat.TTML).isEmpty()); + } +} diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java index 622aaf33d2..13e98b5151 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java @@ -56,13 +56,13 @@ public void testGetViewCount() throws ParsingException { @Test public void testGetUploadDate() throws ParsingException { - assertTrue(extractor.getUploadDate().length() > 0); + assertFalse(extractor.getUploadDate().isEmpty()); } @Test public void testGetUploaderUrl() throws ParsingException { String uploaderUrl = extractor.getUploaderUrl(); - assertTrue(uploaderUrl.startsWith("https://www.youtube.com/channel/")); + assertTrue(uploaderUrl, uploaderUrl.startsWith("https://www.youtube.com/channel/")); } @Test diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java new file mode 100644 index 0000000000..d49d17dce7 --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java @@ -0,0 +1,74 @@ +package org.schabi.newpipe.extractor.services.youtube.stream; + +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.schabi.newpipe.Downloader; +import org.schabi.newpipe.extractor.MediaFormat; +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; +import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory; +import org.schabi.newpipe.extractor.stream.StreamExtractor; +import org.schabi.newpipe.extractor.utils.Localization; + +import java.io.IOException; + +import static org.junit.Assert.*; +import static org.schabi.newpipe.extractor.ServiceList.YouTube; + +/** + * Test for {@link YoutubeStreamLinkHandlerFactory} + */ +public class YoutubeStreamExtractorControversialTest extends YoutubeStreamExtractorBaseTest { + + @BeforeClass + public static void setUp() throws Exception { + NewPipe.init(Downloader.getInstance(), new Localization("GB", "en")); + extractor = (YoutubeStreamExtractor) YouTube + .getStreamExtractor("https://www.youtube.com/watch?v=T4XJQO3qol8"); + extractor.fetchPage(); + } + + @Test + public void testGetInvalidTimeStamp() throws ParsingException { + assertTrue(extractor.getTimeStamp() + "", extractor.getTimeStamp() <= 0); + } + + @Test + public void testGetValidTimeStamp() throws ExtractionException { + StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); + assertEquals(extractor.getTimeStamp() + "", "174"); + } + + @Test + @Ignore + public void testGetAgeLimit() throws ParsingException { + assertEquals(18, extractor.getAgeLimit()); + } + + @Test + public void testGetLength() throws ParsingException { + assertEquals(219, extractor.getLength()); + } + + @Test + public void testGetAudioStreams() throws IOException, ExtractionException { + super.testGetAudioStreams(); + // audio streams are not always necessary + assertFalse(extractor.getAudioStreams().isEmpty()); + } + + @Test + public void testGetSubtitlesListDefault() throws IOException, ExtractionException { + // Video (/view?v=T4XJQO3qol8) set in the setUp() method has no captions => null + assertFalse(extractor.getSubtitlesDefault().isEmpty()); + } + + @Test + public void testGetSubtitlesList() throws IOException, ExtractionException { + // Video (/view?v=T4XJQO3qol8) set in the setUp() method has no captions => null + assertFalse(extractor.getSubtitles(MediaFormat.TTML).isEmpty()); + } +} From f7e569662f84386b5fa537003463ca0449f0d49f Mon Sep 17 00:00:00 2001 From: Stypox Date: Sun, 3 Nov 2019 21:45:01 +0100 Subject: [PATCH 15/16] Ignore related videos test in AgeRestrictedTest Apparently age restricted videos have no related videos (on invidious it's the same, too) --- .../stream/YoutubeStreamExtractorAgeRestrictedTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java index 7efcfaf63f..06fe587319 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java @@ -1,6 +1,7 @@ package org.schabi.newpipe.extractor.services.youtube.stream; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.schabi.newpipe.Downloader; import org.schabi.newpipe.extractor.MediaFormat; @@ -58,6 +59,12 @@ public void testGetAudioStreams() throws IOException, ExtractionException { assertFalse(extractor.getAudioStreams().isEmpty()); } + @Test + @Ignore("Apparently age restricted videos have no related videos") + @Override + public void testGetRelatedVideos() throws IOException, ExtractionException { + super.testGetRelatedVideos(); + } @Test public void testGetSubtitlesListDefault() throws IOException, ExtractionException { From 5381b9a6a2ea2fe3f7e7227695668f9720f1c72e Mon Sep 17 00:00:00 2001 From: Stypox Date: Sun, 3 Nov 2019 22:04:21 +0100 Subject: [PATCH 16/16] Add TimestampTest and simplify other StreamTests Thanks to base class YoutubeStreamExtractorBaseTest --- ...utubeStreamExtractorAgeRestrictedTest.java | 12 ---- .../YoutubeStreamExtractorBaseTest.java | 7 ++ ...utubeStreamExtractorControversialTest.java | 11 ---- .../YoutubeStreamExtractorDefaultTest.java | 16 +---- .../YoutubeStreamExtractorLivestreamTest.java | 66 +------------------ .../YoutubeStreamExtractorTimestampTest.java | 29 ++++++++ 6 files changed, 39 insertions(+), 102 deletions(-) create mode 100644 extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorTimestampTest.java diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java index 06fe587319..e540021b20 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorAgeRestrictedTest.java @@ -10,7 +10,6 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory; -import org.schabi.newpipe.extractor.stream.StreamExtractor; import org.schabi.newpipe.extractor.utils.Localization; import java.io.IOException; @@ -31,17 +30,6 @@ public static void setUp() throws Exception { extractor.fetchPage(); } - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", extractor.getTimeStamp() <= 0); - } - - @Test - public void testGetValidTimeStamp() throws IOException, ExtractionException { - StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); - assertEquals(extractor.getTimeStamp() + "", "174"); - } - @Test public void testGetAgeLimit() throws ParsingException { assertEquals(18, extractor.getAgeLimit()); diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java index 13e98b5151..8252438703 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorBaseTest.java @@ -111,4 +111,11 @@ public void testGetRelatedVideos() throws ExtractionException, IOException { assertFalse(relatedVideos.getItems().isEmpty()); assertTrue(relatedVideos.getErrors().isEmpty()); } + + @Test + public void testGetTimestamp() throws ParsingException { + // invalid timestamp + long timestamp = extractor.getTimeStamp(); + assertTrue( timestamp + "", timestamp <= 0); + } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java index d49d17dce7..2a38435b4c 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorControversialTest.java @@ -31,17 +31,6 @@ public static void setUp() throws Exception { extractor.fetchPage(); } - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", extractor.getTimeStamp() <= 0); - } - - @Test - public void testGetValidTimeStamp() throws ExtractionException { - StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); - assertEquals(extractor.getTimeStamp() + "", "174"); - } - @Test @Ignore public void testGetAgeLimit() throws ParsingException { diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java index 1259067d61..b720bc7d1e 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorDefaultTest.java @@ -55,18 +55,6 @@ public static void setUp() throws Exception { extractor.fetchPage(); } - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", - extractor.getTimeStamp() <= 0); - } - - @Test - public void testGetValidTimeStamp() throws ExtractionException { - StreamExtractor extractor = YouTube.getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); - assertEquals(extractor.getTimeStamp() + "", "174"); - } - @Test public void testGetFullLinksInDescription() throws ParsingException { assertTrue(extractor.getDescription().contains("http://adele.com")); @@ -150,9 +138,7 @@ public void testGetFullLinksInDescription() throws ParsingException { } } - public static class FramesTest { - private static YoutubeStreamExtractor extractor; - + public static class FramesTest extends YoutubeStreamExtractorBaseTest { @BeforeClass public static void setUp() throws Exception { NewPipe.init(Downloader.getInstance(), new Localization("GB", "en")); diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorLivestreamTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorLivestreamTest.java index 3e24b7e36e..1886f294a3 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorLivestreamTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorLivestreamTest.java @@ -20,8 +20,8 @@ import static org.schabi.newpipe.extractor.ExtractorAsserts.assertIsSecureUrl; import static org.schabi.newpipe.extractor.ServiceList.YouTube; -public class YoutubeStreamExtractorLivestreamTest { - private static YoutubeStreamExtractor extractor; +public class YoutubeStreamExtractorLivestreamTest + extends YoutubeStreamExtractorBaseTest { @BeforeClass public static void setUp() throws Exception { @@ -31,36 +31,12 @@ public static void setUp() throws Exception { extractor.fetchPage(); } - @Test - public void testGetInvalidTimeStamp() throws ParsingException { - assertTrue(extractor.getTimeStamp() + "", - extractor.getTimeStamp() <= 0); - } - - @Test - public void testGetTitle() throws ParsingException { - assertFalse(extractor.getName().isEmpty()); - } - - @Test - public void testGetDescription() throws ParsingException { - assertNotNull(extractor.getDescription()); - assertFalse(extractor.getDescription().isEmpty()); - } - @Test public void testGetFullLinksInDescription() throws ParsingException { assertTrue(extractor.getDescription().contains("https://www.instagram.com/nathalie.baraton/")); assertFalse(extractor.getDescription().contains("https://www.instagram.com/nathalie.ba...")); } - @Test - public void testGetUploaderName() throws ParsingException { - assertNotNull(extractor.getUploaderName()); - assertFalse(extractor.getUploaderName().isEmpty()); - } - - @Test public void testGetLength() throws ParsingException { assertEquals(0, extractor.getLength()); @@ -72,41 +48,11 @@ public void testGetViewCount() throws ParsingException { assertTrue(Long.toString(count), count >= 7148995); } - @Test - public void testGetUploadDate() throws ParsingException { - assertTrue(extractor.getUploadDate().length() > 0); - } - @Test public void testGetUploaderUrl() throws ParsingException { assertEquals("https://www.youtube.com/channel/UCSJ4gkVC6NrvII8umztf0Ow", extractor.getUploaderUrl()); } - @Test - public void testGetThumbnailUrl() throws ParsingException { - assertIsSecureUrl(extractor.getThumbnailUrl()); - } - - @Test - public void testGetUploaderAvatarUrl() throws ParsingException { - assertIsSecureUrl(extractor.getUploaderAvatarUrl()); - } - - @Test - public void testGetAudioStreams() throws ExtractionException { - assertFalse(extractor.getAudioStreams().isEmpty()); - } - - @Test - public void testGetVideoStreams() throws ExtractionException { - for (VideoStream s : extractor.getVideoStreams()) { - assertIsSecureUrl(s.url); - assertTrue(s.resolution.length() > 0); - assertTrue(Integer.toString(s.getFormatId()), - 0 <= s.getFormatId() && s.getFormatId() <= 0x100); - } - } - @Test public void testStreamType() throws ParsingException { assertSame(extractor.getStreamType(), StreamType.LIVE_STREAM); @@ -118,14 +64,6 @@ public void testGetDashMpd() throws ParsingException { assertTrue(extractor.getDashMpdUrl(), extractor.getDashMpdUrl().isEmpty()); } - @Test - public void testGetRelatedVideos() throws ExtractionException, IOException { - StreamInfoItemsCollector relatedVideos = extractor.getRelatedStreams(); - Utils.printErrors(relatedVideos.getErrors()); - assertFalse(relatedVideos.getItems().isEmpty()); - assertTrue(relatedVideos.getErrors().isEmpty()); - } - @Test public void testGetSubtitlesListDefault() throws IOException, ExtractionException { assertTrue(extractor.getSubtitlesDefault().isEmpty()); diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorTimestampTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorTimestampTest.java new file mode 100644 index 0000000000..464cfc0691 --- /dev/null +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorTimestampTest.java @@ -0,0 +1,29 @@ +package org.schabi.newpipe.extractor.services.youtube.stream; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.schabi.newpipe.Downloader; +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.exceptions.ParsingException; +import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; +import org.schabi.newpipe.extractor.utils.Localization; + +import static org.junit.Assert.*; +import static org.schabi.newpipe.extractor.ServiceList.YouTube; + +public class YoutubeStreamExtractorTimestampTest extends YoutubeStreamExtractorBaseTest { + + @BeforeClass + public static void setUp() throws Exception { + NewPipe.init(Downloader.getInstance(), new Localization("GB", "en")); + extractor = (YoutubeStreamExtractor) YouTube + .getStreamExtractor("https://youtu.be/FmG385_uUys?t=174"); + extractor.fetchPage(); + } + + @Override + @Test + public void testGetTimestamp() throws ParsingException { + assertEquals(extractor.getTimeStamp(), 174); + } +}