From cc992bdeafefe8175b2e9831271121079ac24000 Mon Sep 17 00:00:00 2001 From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com> Date: Thu, 15 Jan 2026 13:16:27 -0300 Subject: [PATCH 1/4] build: set version to 5.1.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4054cff..17170dd 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.flowingcode.vaadin.addons.demo commons-demo - 5.0.1-SNAPSHOT + 5.1.0-SNAPSHOT Commons Demo Common classes for add-ons demo From ef246d0cbf20d8410d2fa5bc205395fb24ce11df Mon Sep 17 00:00:00 2001 From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:29:34 -0300 Subject: [PATCH 2/4] feat: show DemoSource based on Vaadin version Close #132 --- README.md | 10 ++ .../vaadin/addons/demo/DemoSource.java | 4 +- .../demo/DemoSourceConditionHelper.java | 93 +++++++++++++++++++ .../addons/demo/MultiSourceCodeViewer.java | 20 +++- .../vaadin/addons/demo/SourceCodeTab.java | 3 +- .../vaadin/addons/demo/SplitLayoutDemo.java | 6 +- .../vaadin/addons/demo/TabbedDemo.java | 21 +++-- .../vaadin/addons/demo/MultiSourceDemo.java | 6 +- .../resources/frontend/condition-false.css | 1 + .../resources/frontend/condition-true.css | 1 + 10 files changed, 153 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceConditionHelper.java create mode 100644 src/test/resources/META-INF/resources/frontend/condition-false.css create mode 100644 src/test/resources/META-INF/resources/frontend/condition-true.css diff --git a/README.md b/README.md index 90ab49b..aca8a4a 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,16 @@ For instance, the following source would be rendered as `foo();` in Vaadin 23+, Strictly, the constructor of `SourceCodeViewer` receives a map with arbitrary variables defined by the caller, and `TabbedDemo` defines "vaadin" and "flow" variables. Implementation details in PR https://github.com/FlowingCode/CommonsDemo/pull/44. +The `@DemoSource` annotation also supports a `condition` attribute to control the visibility of the source tab based on the environment. This feature uses the same syntax and operators as the conditional directives. + + +```java +@DemoSource(value = "/src/test/resources/META-INF/resources/frontend/example.css", condition = "vaadin ge 24") +public class MyDemo extends Div { + ... +} +``` + ### Fragment highlighting This feature supports highlighting a source code fragment in order to emphasize a section of the code snippet. diff --git a/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSource.java b/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSource.java index 8b6885c..1ea0b84 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSource.java +++ b/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSource.java @@ -2,7 +2,7 @@ * #%L * Commons Demo * %% - * Copyright (C) 2020 - 2025 Flowing Code + * Copyright (C) 2020 - 2026 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,4 +77,6 @@ /** Source code position in the layout */ SourcePosition sourcePosition() default SourcePosition.SECONDARY; + String condition() default ""; + } diff --git a/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceConditionHelper.java b/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceConditionHelper.java new file mode 100644 index 0000000..977fad3 --- /dev/null +++ b/src/main/java/com/flowingcode/vaadin/addons/demo/DemoSourceConditionHelper.java @@ -0,0 +1,93 @@ +/*- + * #%L + * Commons Demo + * %% + * Copyright (C) 2020 - 2026 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.flowingcode.vaadin.addons.demo; + +import java.util.Map; +import lombok.NonNull; +import lombok.experimental.UtilityClass; + +@UtilityClass +class DemoSourceConditionHelper { + + public boolean eval(String condition, Map env) { + if (condition == null) { + return true; + } + + String[] expr = condition.split(" "); + + if (expr.length == 3) { + String lhs = env.get(expr[0]); + + if (lhs == null) { + return false; + } + + String operator = expr[1]; + String rhs = expr[2]; + + switch (operator) { + case "lt": + return compare(lhs, rhs) < 0; + case "le": + return compare(lhs, rhs) <= 0; + case "eq": + return compare(lhs, rhs) == 0; + case "ge": + return compare(lhs, rhs) >= 0; + case "gt": + return compare(lhs, rhs) > 0; + case "ne": + return compare(lhs, rhs) != 0; + default: + throw new IllegalArgumentException("Unknown operator: " + operator); + } + } else { + throw new IllegalArgumentException("Invalid condition: '" + condition + + "'. Must be exactly 3 components: [VARIABLE] [OPERATOR] [VERSION]"); + } + } + + private int compare(String a, String b) { + String[] aa = split(a); + String[] bb = split(b); + + int minLength = Math.min(aa.length, bb.length); + + for (int i = 0; i < minLength; i++) { + int ai = Integer.parseInt(aa[i]); + int bi = Integer.parseInt(bb[i]); + int c = Integer.compare(ai, bi); + if (c != 0) { + return c; + } + } + + return 0; + } + + private String[] split(@NonNull String version) { + if (!version.matches("^\\d+(\\.\\d+){0,2}$")) { + throw new IllegalArgumentException("Invalid version: '" + version + + "'. Must be 'major', 'major.minor', or major.minor.patch'"); + } + return version.split("\\."); + } +} diff --git a/src/main/java/com/flowingcode/vaadin/addons/demo/MultiSourceCodeViewer.java b/src/main/java/com/flowingcode/vaadin/addons/demo/MultiSourceCodeViewer.java index cbdf2d5..1fccdc2 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/demo/MultiSourceCodeViewer.java +++ b/src/main/java/com/flowingcode/vaadin/addons/demo/MultiSourceCodeViewer.java @@ -2,7 +2,7 @@ * #%L * Commons Demo * %% - * Copyright (C) 2020 - 2025 Flowing Code + * Copyright (C) 2020 - 2026 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.tabs.Tab; import elemental.json.JsonValue; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; @@ -42,6 +43,12 @@ public class MultiSourceCodeViewer extends Div { private EnhancedTabs tabs; public MultiSourceCodeViewer(List sourceCodeTabs, Map properties) { + sourceCodeTabs = new ArrayList<>(sourceCodeTabs); + sourceCodeTabs.removeIf(tab -> !DemoSourceConditionHelper.eval(tab.getCondition(), properties)); + if (sourceCodeTabs.isEmpty()) { + return; + } + if (sourceCodeTabs.size() > 1) { tabs = new EnhancedTabs(createTabs(sourceCodeTabs)); tabs.addSelectedChangeListener(ev -> onTabSelected(ev.getSelectedTab())); @@ -69,6 +76,10 @@ public MultiSourceCodeViewer(List sourceCodeTabs, Map sourceCodeTabs) { return sourceCodeTabs.stream().map(this::createTab).toArray(Tab[]::new); } @@ -134,7 +145,12 @@ private void fetchContents(String url, String language) { } public SourcePosition getSourcePosition() { - return (SourcePosition) ComponentUtil.getData(selectedTab, DATA_POSITION); + if (selectedTab != null) { + return (SourcePosition) ComponentUtil.getData(selectedTab, DATA_POSITION); + } else { + return SourcePosition.SECONDARY; + } + } private Optional findTabWithFilename(String filename) { diff --git a/src/main/java/com/flowingcode/vaadin/addons/demo/SourceCodeTab.java b/src/main/java/com/flowingcode/vaadin/addons/demo/SourceCodeTab.java index 31f7632..aa2df50 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/demo/SourceCodeTab.java +++ b/src/main/java/com/flowingcode/vaadin/addons/demo/SourceCodeTab.java @@ -2,7 +2,7 @@ * #%L * Commons Demo * %% - * Copyright (C) 2020 - 2024 Flowing Code + * Copyright (C) 2020 - 2026 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ public class SourceCodeTab { private final String url; private String caption; private String language; + private String condition; @NonNull private final SourcePosition sourcePosition; diff --git a/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java b/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java index 03ba67d..5762111 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java +++ b/src/main/java/com/flowingcode/vaadin/addons/demo/SplitLayoutDemo.java @@ -2,7 +2,7 @@ * #%L * Commons Demo * %% - * Copyright (C) 2020 - 2023 Flowing Code + * Copyright (C) 2020 - 2026 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,6 +54,10 @@ public SplitLayoutDemo(Component demo, List tabs) { getContent().setSizeFull(); } + public boolean isEmpty() { + return code.isEmpty(); + } + private void setSourcePosition(SourcePosition position) { if (!position.equals(sourcePosition)) { getContent().removeAll(); diff --git a/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java b/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java index 7f7fada..d8a5c3d 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java +++ b/src/main/java/com/flowingcode/vaadin/addons/demo/TabbedDemo.java @@ -2,7 +2,7 @@ * #%L * Commons Demo * %% - * Copyright (C) 2020 - 2025 Flowing Code + * Copyright (C) 2020 - 2026 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -181,16 +181,21 @@ public void showRouterLayoutContent(HasElement content) { } if (!sourceTabs.isEmpty()) { - content = new SplitLayoutDemo(demo, sourceTabs); - currentLayout = (SplitLayoutDemo) content; + currentLayout = new SplitLayoutDemo(demo, sourceTabs); + if (currentLayout.isEmpty()) { + demo.getElement().removeAttribute("slot"); + currentLayout = null; + } + } + + if (currentLayout != null) { + content = currentLayout; if (splitOrientation != null) { setOrientation(splitOrientation); updateSplitterPosition(); } - if (currentLayout != null) { - setupDemoHelperButton(currentLayout.getContent().getPrimaryComponent().getClass()); - } + setupDemoHelperButton(currentLayout.getContent().getPrimaryComponent().getClass()); } else { currentLayout = null; demo.getElement().getStyle().set("height", "100%"); @@ -245,6 +250,10 @@ private Optional createSourceCodeTab(Class annotatedClass, Dem builder.language(annotation.caption()); } + if (!annotation.condition().isEmpty()) { + builder.condition(annotation.condition()); + } + builder.sourcePosition(annotation.sourcePosition()); return Optional.of(builder.build()); diff --git a/src/test/java/com/flowingcode/vaadin/addons/demo/MultiSourceDemo.java b/src/test/java/com/flowingcode/vaadin/addons/demo/MultiSourceDemo.java index fcfa8ee..e7e7751 100644 --- a/src/test/java/com/flowingcode/vaadin/addons/demo/MultiSourceDemo.java +++ b/src/test/java/com/flowingcode/vaadin/addons/demo/MultiSourceDemo.java @@ -1,7 +1,7 @@ /*- * #%L * %% - * Copyright (C) 2020 - 2024 Flowing Code + * Copyright (C) 2020 - 2026 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,9 +29,13 @@ // show-source @DemoSource // show-source @DemoSource(clazz = AdditionalSources.class) // show-source @DemoSource("/src/test/resources/META-INF/resources/frontend/multi-source-demo.css") +// show-source @DemoSource(value="/src/test/resources/META-INF/resources/frontend/condition-true.css", condition = "vaadin ge 14") +// show-source @DemoSource(value="/src/test/resources/META-INF/resources/frontend/condition-false.css", condition = "vaadin eq 0") @DemoSource @DemoSource(clazz = AdditionalSources.class) @DemoSource("/src/test/resources/META-INF/resources/frontend/multi-source-demo.css") +@DemoSource(value="/src/test/resources/META-INF/resources/frontend/condition-true.css", condition = "vaadin ge 14") +@DemoSource(value="/src/test/resources/META-INF/resources/frontend/condition-false.css", condition = "vaadin eq 0") @StyleSheet("./multi-source-demo.css") public class MultiSourceDemo extends Div { public MultiSourceDemo() { diff --git a/src/test/resources/META-INF/resources/frontend/condition-false.css b/src/test/resources/META-INF/resources/frontend/condition-false.css new file mode 100644 index 0000000..6a37837 --- /dev/null +++ b/src/test/resources/META-INF/resources/frontend/condition-false.css @@ -0,0 +1 @@ +/** This source file is conditionally hidden. */ \ No newline at end of file diff --git a/src/test/resources/META-INF/resources/frontend/condition-true.css b/src/test/resources/META-INF/resources/frontend/condition-true.css new file mode 100644 index 0000000..c63b5c4 --- /dev/null +++ b/src/test/resources/META-INF/resources/frontend/condition-true.css @@ -0,0 +1 @@ +/** This source is shown when Vaadin version is 14+ */ \ No newline at end of file From 4297702a36b523bf4f3b347c92da8895e8c2fadd Mon Sep 17 00:00:00 2001 From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com> Date: Thu, 15 Jan 2026 13:12:29 -0300 Subject: [PATCH 3/4] test: upgrade webdrivermanager to 6.3.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 17170dd..1ebeb38 100644 --- a/pom.xml +++ b/pom.xml @@ -130,7 +130,7 @@ io.github.bonigarcia webdrivermanager - 5.3.0 + 6.3.2 test From e11ddd5d03d4d4fab3e2b18dca5f7364d7cffc58 Mon Sep 17 00:00:00 2001 From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com> Date: Thu, 15 Jan 2026 13:13:01 -0300 Subject: [PATCH 4/4] test: add integration tests --- .../vaadin/addons/demo/it/TabbedDemoView.java | 67 +++++++++ .../addons/demo/it/TabbedDemoViewIT.java | 137 ++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 src/test/java/com/flowingcode/vaadin/addons/demo/it/TabbedDemoView.java create mode 100644 src/test/java/com/flowingcode/vaadin/addons/demo/it/TabbedDemoViewIT.java diff --git a/src/test/java/com/flowingcode/vaadin/addons/demo/it/TabbedDemoView.java b/src/test/java/com/flowingcode/vaadin/addons/demo/it/TabbedDemoView.java new file mode 100644 index 0000000..0aebc70 --- /dev/null +++ b/src/test/java/com/flowingcode/vaadin/addons/demo/it/TabbedDemoView.java @@ -0,0 +1,67 @@ +/*- + * #%L + * Commons Demo + * %% + * Copyright (C) 2020 - 2026 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.flowingcode.vaadin.addons.demo.it; + +import com.flowingcode.vaadin.addons.GithubLink; +import com.flowingcode.vaadin.addons.demo.AdHocDemo; +import com.flowingcode.vaadin.addons.demo.DemoSource; +import com.flowingcode.vaadin.addons.demo.TabbedDemo; +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.router.Route; + +@SuppressWarnings("serial") +@GithubLink("https://github.com/FlowingCode/CommonsDemo") +public class TabbedDemoView extends TabbedDemo { + + public TabbedDemoView() { + addDemo(TabbedDemoViewNoSource.class); + addDemo(TabbedDemoViewSingleSource.class); + addDemo(TabbedDemoViewMultiSource.class); + addDemo(TabbedDemoViewConditionalTrue.class); + addDemo(TabbedDemoViewConditionalFalse.class); + } + + protected abstract static class AbstractDemoView extends Div { + public AbstractDemoView() { + add(new Span(this.getClass().getSimpleName())); + } + } + + @Route(value = "it/tabbed-demo-no-source", layout = TabbedDemoView.class) + public static class TabbedDemoViewNoSource extends AbstractDemoView { } + + @DemoSource(clazz = TabbedDemoView.class) + @Route(value = "it/tabbed-demo-single-source", layout = TabbedDemoView.class) + public static class TabbedDemoViewSingleSource extends AbstractDemoView { } + + @DemoSource(clazz = TabbedDemoView.class) + @DemoSource(clazz = AdHocDemo.class) + @Route(value = "it/tabbed-demo-multi-source", layout = TabbedDemoView.class) + public static class TabbedDemoViewMultiSource extends AbstractDemoView { } + + @DemoSource(clazz = TabbedDemoView.class, condition = "vaadin ge 14") + @Route(value = "it/tabbed-demo-conditional-true", layout = TabbedDemoView.class) + public static class TabbedDemoViewConditionalTrue extends AbstractDemoView { } + + @DemoSource(clazz = TabbedDemoView.class, condition = "vaadin eq 0") + @Route(value = "it/tabbed-demo-conditional-false", layout = TabbedDemoView.class) + public static class TabbedDemoViewConditionalFalse extends AbstractDemoView { } +} diff --git a/src/test/java/com/flowingcode/vaadin/addons/demo/it/TabbedDemoViewIT.java b/src/test/java/com/flowingcode/vaadin/addons/demo/it/TabbedDemoViewIT.java new file mode 100644 index 0000000..411c816 --- /dev/null +++ b/src/test/java/com/flowingcode/vaadin/addons/demo/it/TabbedDemoViewIT.java @@ -0,0 +1,137 @@ +/*- + * #%L + * Commons Demo + * %% + * Copyright (C) 2020 - 2026 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.flowingcode.vaadin.addons.demo.it; + +import static org.hamcrest.CoreMatchers.not; +import com.flowingcode.vaadin.addons.demo.it.TabbedDemoView.TabbedDemoViewConditionalFalse; +import com.flowingcode.vaadin.addons.demo.it.TabbedDemoView.TabbedDemoViewConditionalTrue; +import com.flowingcode.vaadin.addons.demo.it.TabbedDemoView.TabbedDemoViewMultiSource; +import com.flowingcode.vaadin.addons.demo.it.TabbedDemoView.TabbedDemoViewNoSource; +import com.flowingcode.vaadin.addons.demo.it.TabbedDemoView.TabbedDemoViewSingleSource; +import com.vaadin.flow.component.Component; +import com.vaadin.flow.router.Route; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.SearchContext; + +public class TabbedDemoViewIT extends AbstractViewTest { + + private SourceCodeViewerElement viewer; + + protected void open(Class clazz) { + if (viewer != null) { + throw new IllegalStateException(); + } + getDriver().get(getURL(clazz.getAnnotation(Route.class).value())); + getCommandExecutor().waitForVaadin(); + getDriver().findElement(By.id("content")); + } + + public static Matcher hasElement(String cssSelector) { + return new TypeSafeMatcher<>() { + + @Override + protected boolean matchesSafely(SearchContext container) { + return !container.findElements(By.cssSelector(cssSelector)).isEmpty(); + } + + @Override + public void describeTo(Description description) { + description.appendText("a page containing element: ").appendValue(cssSelector); + } + + @Override + protected void describeMismatchSafely(SearchContext container, + Description mismatchDescription) { + mismatchDescription.appendText("no elements matched selector: ").appendValue(cssSelector); + } + }; + } + + private Matcher hasPrimaryCodeTabs() { + return hasElement("[slot='primary'] vaadin-menu-bar"); + } + + private Matcher hasPrimaryCodeViewer() { + return hasElement("[slot='primary'] code-viewer"); + } + + private Matcher hasSecondaryCodeTabs() { + return hasElement("[slot='secondary'] vaadin-menu-bar"); + } + + private Matcher hasSecondaryCodeViewer() { + return hasElement("[slot='secondary'] code-viewer"); + } + + private void assertThat(Matcher matcher) { + Assert.assertThat(getDriver(), matcher); + } + + @Test + public void testSimpleNoSource() { + open(TabbedDemoViewNoSource.class); + assertThat(not(hasPrimaryCodeTabs())); + assertThat(not(hasPrimaryCodeViewer())); + assertThat(not(hasSecondaryCodeTabs())); + assertThat(not(hasSecondaryCodeViewer())); + } + + @Test + public void testSimpleSingleSource() { + open(TabbedDemoViewSingleSource.class); + assertThat(not(hasPrimaryCodeTabs())); + assertThat(not(hasPrimaryCodeViewer())); + assertThat(not(hasSecondaryCodeTabs())); + assertThat(hasSecondaryCodeViewer()); + } + + @Test + public void testSimpleMultiSource() { + open(TabbedDemoViewMultiSource.class); + assertThat(not(hasPrimaryCodeTabs())); + assertThat(not(hasPrimaryCodeViewer())); + assertThat(hasSecondaryCodeTabs()); + assertThat(hasSecondaryCodeViewer()); + } + + @Test + public void testSimpleConditionalTrue() { + open(TabbedDemoViewConditionalTrue.class); + assertThat(not(hasPrimaryCodeTabs())); + assertThat(not(hasPrimaryCodeViewer())); + assertThat(not(hasSecondaryCodeTabs())); + assertThat(hasSecondaryCodeViewer()); + } + + @Test + public void testSimpleConditionalFalse() { + open(TabbedDemoViewConditionalFalse.class); + assertThat(not(hasPrimaryCodeTabs())); + assertThat(not(hasPrimaryCodeViewer())); + assertThat(not(hasSecondaryCodeTabs())); + assertThat(not(hasSecondaryCodeViewer())); + } + +}