// Copyright 2019 Google LLC // // 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 // // https://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. // Tests to ensure that conditional fields work. #include #include #include "gtest/gtest.h" #include "testdata/condition.emb.h" namespace emboss { namespace test { namespace { TEST(Conditional, WithConditionTrueFieldsAreOk) { ::std::uint8_t buffer[2] = {0, 0}; auto writer = BasicConditionalWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); EXPECT_TRUE(writer.x().Ok()); EXPECT_TRUE(writer.xc().Ok()); } TEST(Conditional, WithConditionTrueAllFieldsAreReadable) { ::std::uint8_t buffer[2] = {0, 2}; auto writer = BasicConditionalWriter(buffer, sizeof buffer); EXPECT_EQ(0, writer.x().Read()); EXPECT_EQ(2, writer.xc().Read()); } TEST(Conditional, WithConditionTrueConditionalFieldIsWritable) { ::std::uint8_t buffer1[2] = {0, 2}; auto writer1 = BasicConditionalWriter(buffer1, sizeof buffer1); EXPECT_TRUE(writer1.xc().TryToWrite(3)); EXPECT_EQ(3, buffer1[1]); ::std::uint8_t buffer2[2] = {0, 0}; auto writer2 = BasicConditionalWriter(buffer2, sizeof buffer2); EXPECT_FALSE(writer2.xc().Equals(writer1.xc())); EXPECT_TRUE(writer2.xc().TryToCopyFrom(writer1.xc())); EXPECT_TRUE(writer2.xc().Equals(writer1.xc())); EXPECT_EQ(3, buffer2[1]); } TEST(Conditional, WithConditionFalseStructIsOkButConditionalFieldIsNot) { ::std::uint8_t buffer[2] = {1, 2}; auto writer = BasicConditionalWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); EXPECT_TRUE(writer.x().Ok()); EXPECT_FALSE(writer.xc().Ok()); } #if EMBOSS_CHECK_ABORTS TEST(Conditional, BasicConditionFalseReadCrashes) { ::std::uint8_t buffer[2] = {1, 2}; auto writer = BasicConditionalWriter(buffer, sizeof buffer); EXPECT_DEATH(writer.xc().Read(), ""); } TEST(Conditional, BasicConditionFalseWriteCrashes) { ::std::uint8_t buffer[2] = {1, 2}; auto writer = BasicConditionalWriter(buffer, sizeof buffer); EXPECT_DEATH(writer.xc().Write(3), ""); } #endif // EMBOSS_CHECK_ABORTS TEST(Conditional, BasicConditionTrueSizeIncludesConditionalField) { ::std::uint8_t buffer[2] = {0, 2}; auto writer = BasicConditionalWriter(buffer, sizeof buffer); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_EQ(2, BasicConditional::MaxSizeInBytes()); EXPECT_EQ(1, BasicConditional::MinSizeInBytes()); EXPECT_EQ(2, writer.MaxSizeInBytes().Read()); EXPECT_EQ(1, writer.MinSizeInBytes().Read()); } TEST(Conditional, BasicConditionFalseSizeDoesNotIncludeConditionalField) { ::std::uint8_t buffer[2] = {1, 2}; auto writer = BasicConditionalWriter(buffer, sizeof buffer); EXPECT_EQ(1U, writer.SizeInBytes()); EXPECT_EQ(2, writer.MaxSizeInBytes().Read()); EXPECT_EQ(1, writer.MinSizeInBytes().Read()); } TEST(Conditional, WithConditionFalseStructIsOkWhenBufferIsSmall) { ::std::uint8_t buffer[1] = {1}; auto writer = BasicConditionalWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); EXPECT_TRUE(writer.x().Ok()); EXPECT_FALSE(writer.xc().Ok()); } TEST(Conditional, WithConditionTrueStructIsNotOkWhenBufferIsSmall) { ::std::uint8_t buffer[1] = {0}; auto writer = BasicConditionalWriter(buffer, sizeof buffer); EXPECT_FALSE(writer.Ok()); EXPECT_TRUE(writer.x().Ok()); EXPECT_TRUE(writer.has_xc().Known()); EXPECT_TRUE(writer.has_xc().Value()); EXPECT_FALSE(writer.xc().Ok()); } TEST(Conditional, WithNegativeConditionTrueFieldsAreOk) { ::std::uint8_t buffer[2] = {1, 0}; auto writer = NegativeConditionalWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); EXPECT_TRUE(writer.x().Ok()); EXPECT_TRUE(writer.xc().Ok()); } TEST(Conditional, WithNegativeConditionTrueAllFieldsAreReadable) { ::std::uint8_t buffer[2] = {1, 2}; auto writer = NegativeConditionalWriter(buffer, sizeof buffer); EXPECT_EQ(1, writer.x().Read()); EXPECT_EQ(2, writer.xc().Read()); } TEST(Conditional, WithNegativeConditionTrueConditionalFieldIsWritable) { ::std::uint8_t buffer1[2] = {1, 2}; auto writer1 = NegativeConditionalWriter(buffer1, sizeof buffer1); EXPECT_TRUE(writer1.xc().TryToWrite(3)); EXPECT_EQ(3, buffer1[1]); ::std::uint8_t buffer2[2] = {1, 0}; auto writer2 = NegativeConditionalWriter(buffer2, sizeof buffer2); EXPECT_FALSE(writer2.xc().Equals(writer1.xc())); EXPECT_TRUE(writer2.xc().TryToCopyFrom(writer1.xc())); EXPECT_TRUE(writer2.xc().Equals(writer1.xc())); EXPECT_EQ(3, buffer2[1]); } TEST(Conditional, WithNegativeConditionFalseStructIsOkButConditionalFieldIsNot) { ::std::uint8_t buffer[2] = {0, 2}; auto writer = NegativeConditionalWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); EXPECT_TRUE(writer.x().Ok()); EXPECT_FALSE(writer.xc().Ok()); } TEST(Conditional, NegativeConditionFalseReadCrashes) { ::std::uint8_t buffer1[2] = {0, 2}; auto writer1 = NegativeConditionalWriter(buffer1, sizeof buffer1); #if EMBOSS_CHECK_ABORTS EXPECT_DEATH(writer1.xc().Read(), ""); #endif // EMBOSS_CHECK_ABORTS ::std::uint8_t buffer2[2] = {0, 0}; auto writer2 = BasicConditionalWriter(buffer2, sizeof buffer2); EXPECT_TRUE(writer2.xc().CouldWriteValue(2)); EXPECT_EQ(writer2.xc().Read(), 0); EXPECT_FALSE(writer2.xc().TryToCopyFrom(writer1.xc())); EXPECT_EQ(writer2.xc().Read(), 0); } TEST(Conditional, NegativeConditionFalseWriteCrashes) { ::std::uint8_t buffer1[2] = {0, 2}; auto writer1 = NegativeConditionalWriter(buffer1, sizeof buffer1); #if EMBOSS_CHECK_ABORTS EXPECT_DEATH(writer1.xc().Write(3), ""); #endif // EMBOSS_CHECK_ABORTS ::std::uint8_t buffer2[2] = {0, 2}; auto writer2 = NegativeConditionalWriter(buffer2, sizeof buffer2); EXPECT_FALSE(writer2.xc().TryToCopyFrom(writer1.xc())); } TEST(Conditional, NegativeConditionTrueSizeIncludesConditionalField) { ::std::uint8_t buffer[2] = {1, 2}; auto writer = NegativeConditionalWriter(buffer, sizeof buffer); EXPECT_EQ(2U, writer.SizeInBytes()); } TEST(Conditional, NegativeConditionFalseSizeDoesNotIncludeConditionalField) { ::std::uint8_t buffer[2] = {0, 2}; auto writer = NegativeConditionalWriter(buffer, sizeof buffer); EXPECT_EQ(1U, writer.SizeInBytes()); } TEST(Conditional, WithNegativeConditionFalseStructIsOkWhenBufferIsSmall) { ::std::uint8_t buffer[1] = {0}; auto writer = NegativeConditionalWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); EXPECT_TRUE(writer.x().Ok()); EXPECT_FALSE(writer.xc().Ok()); } TEST(Conditional, WithNegativeConditionTrueStructIsNotOkWhenBufferIsSmall) { ::std::uint8_t buffer[1] = {1}; auto writer = NegativeConditionalWriter(buffer, sizeof buffer); EXPECT_FALSE(writer.Ok()); EXPECT_TRUE(writer.x().Ok()); EXPECT_TRUE(writer.has_xc().Known()); EXPECT_TRUE(writer.has_xc().Value()); EXPECT_FALSE(writer.xc().Ok()); } TEST(Conditional, SizeIncludesUnconditionalFieldsThatOverlapWithConditionalFields) { ::std::uint8_t buffer[2] = {1, 2}; auto writer = ConditionalAndUnconditionalOverlappingFinalFieldWriter( buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); EXPECT_EQ(2U, writer.SizeInBytes()); } TEST(Conditional, SizeIsConstantWhenUnconditionalFieldsOverlapWithConditionalFields) { EXPECT_EQ( 2U, ConditionalAndUnconditionalOverlappingFinalFieldWriter::SizeInBytes()); } TEST(Conditional, WhenConditionalFieldIsFirstSizeIsConstant) { EXPECT_EQ(2U, ConditionalBasicConditionalFieldFirstWriter::SizeInBytes()); } TEST(Conditional, WhenConditionIsFalseDynamicallyPlacedFieldDoesNotAffectSize) { ::std::uint8_t buffer[3] = {1, 0, 10}; auto writer = ConditionalAndDynamicLocationWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); EXPECT_EQ(3U, writer.SizeInBytes()); } TEST(Conditional, WhenConditionIsTrueDynamicallyPlacedFieldDoesAffectSize) { ::std::uint8_t buffer[4] = {0, 0, 3, 0}; auto writer = ConditionalAndDynamicLocationWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); EXPECT_EQ(4U, writer.SizeInBytes()); } TEST(Conditional, WhenConditionIsTrueDynamicallyPlacedFieldOutOfRangeIsError) { ::std::uint8_t buffer[3] = {0, 0, 3}; auto writer = ConditionalAndDynamicLocationWriter(buffer, sizeof buffer); EXPECT_FALSE(writer.Ok()); EXPECT_EQ(4U, writer.SizeInBytes()); } TEST(Conditional, ConditionUsesMinInt) { ::std::uint8_t buffer[2] = {0, 0}; auto view = MakeConditionUsesMinIntView(buffer, sizeof buffer); EXPECT_TRUE(view.Ok()); EXPECT_FALSE(view.has_xc().ValueOr(true)); EXPECT_EQ(1U, view.SizeInBytes()); buffer[0] = 0x80; EXPECT_TRUE(view.Ok()); EXPECT_EQ(-0x80, view.x().Read()); EXPECT_TRUE(view.has_xc().ValueOr(false)); EXPECT_EQ(2U, view.SizeInBytes()); } TEST(Conditional, StructWithNestedConditionIsNotOkWhenOuterConditionDoesNotExist) { ::std::uint8_t buffer[3] = {1, 0, 3}; auto writer = NestedConditionalWriter(buffer, sizeof buffer); ASSERT_FALSE(writer.IntrinsicSizeInBytes().Ok()); ASSERT_FALSE((writer.xc().Ok())); ASSERT_FALSE(writer.SizeIsKnown()); ASSERT_FALSE(writer.IsComplete()); ASSERT_FALSE(writer.Ok()); ASSERT_TRUE(writer.has_xc().Known()); ASSERT_FALSE(writer.has_xc().Value()); ASSERT_FALSE(writer.has_xcc().Known()); } TEST(Conditional, StructWithCorrectNestedConditionIsOkWhenOuterConditionDoesNotExist) { ::std::uint8_t buffer[3] = {1, 0, 3}; auto writer = CorrectNestedConditionalWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.IsComplete()); EXPECT_TRUE(writer.Ok()); EXPECT_TRUE(writer.has_xc().Known()); EXPECT_FALSE(writer.has_xc().Value()); EXPECT_TRUE(writer.has_xcc().Known()); EXPECT_FALSE(writer.has_xcc().Value()); EXPECT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(1U, writer.SizeInBytes()); } TEST(Conditional, StructWithNestedConditionIsOkWhenOuterConditionExists) { ::std::uint8_t buffer[3] = {0, 1, 3}; auto writer = NestedConditionalWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_TRUE(writer.has_xc().Known()); EXPECT_TRUE(writer.has_xc().Value()); EXPECT_TRUE(writer.has_xcc().Known()); EXPECT_FALSE(writer.has_xcc().Value()); EXPECT_EQ(2U, writer.SizeInBytes()); } TEST(Conditional, AlwaysMissingFieldDoesNotContributeToStaticSize) { EXPECT_EQ(0U, OnlyAlwaysFalseConditionWriter::SizeInBytes()); EXPECT_EQ(1U, AlwaysFalseConditionWriter::SizeInBytes()); } TEST(Conditional, AlwaysMissingFieldDoesNotContributeToSize) { ::std::uint8_t buffer[1] = {0}; auto view = MakeAlwaysFalseConditionDynamicSizeView(buffer, sizeof buffer); ASSERT_TRUE(view.SizeIsKnown()); EXPECT_EQ(1U, view.SizeInBytes()); } TEST(Conditional, StructIsOkWithAlwaysMissingField) { ::std::uint8_t buffer[1] = {0}; auto writer = AlwaysFalseConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(1U, writer.SizeInBytes()); EXPECT_EQ(1U, AlwaysFalseConditionView::SizeInBytes()); } TEST(Conditional, StructIsOkWithOnlyAlwaysMissingField) { ::std::uint8_t buffer[1] = {0}; auto writer = OnlyAlwaysFalseConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(0U, writer.SizeInBytes()); EXPECT_EQ(0U, OnlyAlwaysFalseConditionView::SizeInBytes()); } TEST(Conditional, ConditionDoesNotBlockStaticSize) { EXPECT_EQ(3U, ConditionDoesNotContributeToSizeView::SizeInBytes()); } TEST(Conditional, EqualsHaveAllFields) { ::std::array buf_a = {0, 1}; ::std::array buf_b = {0, 1}; EXPECT_EQ(buf_a, buf_b); auto a = BasicConditionalWriter(&buf_a); auto a_const = BasicConditionalWriter( static_cast *>(&buf_a)); auto b = BasicConditionalWriter(&buf_b); EXPECT_TRUE(a.has_xc().Known()); EXPECT_TRUE(a.has_xc().Value()); EXPECT_TRUE(b.has_xc().Known()); EXPECT_TRUE(b.has_xc().Value()); EXPECT_TRUE(a.Equals(a)); EXPECT_TRUE(a.UncheckedEquals(a)); EXPECT_TRUE(b.Equals(b)); EXPECT_TRUE(b.UncheckedEquals(b)); EXPECT_TRUE(a.Equals(b)); EXPECT_TRUE(a.UncheckedEquals(b)); EXPECT_TRUE(b.Equals(a)); EXPECT_TRUE(b.UncheckedEquals(a)); EXPECT_TRUE(a_const.Equals(b)); EXPECT_TRUE(a_const.UncheckedEquals(b)); EXPECT_TRUE(b.Equals(a_const)); EXPECT_TRUE(b.UncheckedEquals(a_const)); b.xc().Write(b.xc().Read() + 1); EXPECT_FALSE(a.Equals(b)); EXPECT_FALSE(a.UncheckedEquals(b)); EXPECT_FALSE(b.Equals(a)); EXPECT_FALSE(b.UncheckedEquals(a)); EXPECT_FALSE(a_const.Equals(b)); EXPECT_FALSE(a_const.UncheckedEquals(b)); EXPECT_FALSE(b.Equals(a_const)); EXPECT_FALSE(b.UncheckedEquals(a_const)); } TEST(Conditional, EqualsOneViewMissingField) { ::std::array buf_a = {0, 1}; ::std::array buf_b = {1, 1}; EXPECT_NE(buf_a, buf_b); auto a = BasicConditionalWriter(&buf_a); auto b = BasicConditionalWriter(&buf_b); EXPECT_TRUE(a.has_xc().Known()); EXPECT_TRUE(a.has_xc().Value()); EXPECT_TRUE(b.has_xc().Known()); EXPECT_FALSE(b.has_xc().Value()); EXPECT_FALSE(a.Equals(b)); EXPECT_FALSE(a.UncheckedEquals(b)); EXPECT_FALSE(b.Equals(a)); EXPECT_FALSE(b.UncheckedEquals(a)); } TEST(Conditional, EqualsBothFieldsMissing) { ::std::array buf_a = {1, 1}; ::std::array buf_b = {1, 1}; EXPECT_EQ(buf_a, buf_b); auto a = BasicConditionalWriter(&buf_a); auto a_const = BasicConditionalWriter( static_cast *>(&buf_a)); auto b = BasicConditionalWriter(&buf_b); EXPECT_TRUE(a.has_xc().Known()); EXPECT_FALSE(a.has_xc().Value()); EXPECT_TRUE(b.has_xc().Known()); EXPECT_FALSE(b.has_xc().Value()); EXPECT_TRUE(a.Equals(b)); EXPECT_TRUE(a.UncheckedEquals(b)); EXPECT_TRUE(b.Equals(a)); EXPECT_TRUE(b.UncheckedEquals(a)); EXPECT_TRUE(a_const.Equals(b)); EXPECT_TRUE(a_const.UncheckedEquals(b)); EXPECT_TRUE(b.Equals(a_const)); EXPECT_TRUE(b.UncheckedEquals(a_const)); ++buf_b[1]; EXPECT_NE(buf_a, buf_b); EXPECT_TRUE(a.Equals(b)); EXPECT_TRUE(a.UncheckedEquals(b)); EXPECT_TRUE(b.Equals(a)); EXPECT_TRUE(b.UncheckedEquals(a)); EXPECT_TRUE(a_const.Equals(b)); EXPECT_TRUE(a_const.UncheckedEquals(b)); EXPECT_TRUE(b.Equals(a_const)); EXPECT_TRUE(b.UncheckedEquals(a_const)); } TEST(Conditional, TrueEnumBasedCondition) { ::std::uint8_t buffer[2] = {1}; auto writer = EnumConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_TRUE(writer.has_xc().Value()); EXPECT_EQ(0, writer.xc().Read()); EXPECT_TRUE(writer.has_xc2().Value()); EXPECT_EQ(0, writer.xc2().Read()); } TEST(Conditional, FalseEnumBasedCondition) { ::std::uint8_t buffer[2] = {0}; auto writer = EnumConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(1U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); EXPECT_FALSE(writer.has_xc().Value()); EXPECT_FALSE(writer.xc2().Ok()); EXPECT_FALSE(writer.has_xc2().Value()); } TEST(Conditional, TrueEnumBasedNegativeCondition) { ::std::uint8_t buffer[2] = {0}; auto writer = NegativeEnumConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_EQ(0, writer.xc().Read()); } TEST(Conditional, FalseEnumBasedNegativeCondition) { ::std::uint8_t buffer[2] = {1}; auto writer = NegativeEnumConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(1U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(LessThanConditional, LessThan) { ::std::uint8_t buffer[2] = {4}; auto writer = LessThanConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(LessThanConditional, Equal) { ::std::uint8_t buffer[2] = {5}; auto writer = LessThanConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(1U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(LessThanConditional, GreaterThan) { ::std::uint8_t buffer[2] = {6}; auto writer = LessThanConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(1U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(LessThanOrEqualConditional, LessThan) { ::std::uint8_t buffer[2] = {4}; auto writer = LessThanOrEqualConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(LessThanOrEqualConditional, Equal) { ::std::uint8_t buffer[2] = {5}; auto writer = LessThanOrEqualConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(LessThanOrEqualConditional, GreaterThan) { ::std::uint8_t buffer[2] = {6}; auto writer = LessThanOrEqualConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(1U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(GreaterThanConditional, LessThan) { ::std::uint8_t buffer[2] = {4}; auto writer = GreaterThanConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(1U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(GreaterThanConditional, Equal) { ::std::uint8_t buffer[2] = {5}; auto writer = GreaterThanConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(1U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(GreaterThanConditional, GreaterThan) { ::std::uint8_t buffer[2] = {6}; auto writer = GreaterThanConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(GreaterThanOrEqualConditional, LessThan) { ::std::uint8_t buffer[2] = {4}; auto writer = GreaterThanOrEqualConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(1U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(GreaterThanOrEqualConditional, Equal) { ::std::uint8_t buffer[2] = {5}; auto writer = GreaterThanOrEqualConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(GreaterThanOrEqualConditional, GreaterThan) { ::std::uint8_t buffer[2] = {6}; auto writer = GreaterThanOrEqualConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(RangeConditional, ValueTooSmall) { ::std::uint8_t buffer[3] = {1, 9}; auto writer = RangeConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(RangeConditional, ValueTooLarge) { ::std::uint8_t buffer[3] = {11, 12}; auto writer = RangeConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(RangeConditional, ValuesSwapped) { ::std::uint8_t buffer[3] = {8, 7}; auto writer = RangeConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(RangeConditional, True) { ::std::uint8_t buffer[3] = {7, 8}; auto writer = RangeConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(3U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(ReverseRangeConditional, ValueTooSmall) { ::std::uint8_t buffer[3] = {1, 9}; auto writer = ReverseRangeConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(ReverseRangeConditional, ValueTooLarge) { ::std::uint8_t buffer[3] = {11, 12}; auto writer = ReverseRangeConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(ReverseRangeConditional, ValuesSwapped) { ::std::uint8_t buffer[3] = {8, 7}; auto writer = ReverseRangeConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(ReverseRangeConditional, True) { ::std::uint8_t buffer[3] = {7, 8}; auto writer = ReverseRangeConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(3U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(AndConditional, BothFalse) { ::std::uint8_t buffer[3] = {1, 1}; auto writer = AndConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(AndConditional, FirstFalse) { ::std::uint8_t buffer[3] = {1, 5}; auto writer = AndConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(AndConditional, SecondFalse) { ::std::uint8_t buffer[3] = {5, 1}; auto writer = AndConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(AndConditional, BothTrue) { ::std::uint8_t buffer[3] = {5, 5}; auto writer = AndConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(3U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(OrConditional, BothFalse) { ::std::uint8_t buffer[3] = {1, 1}; auto writer = OrConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(2U, writer.SizeInBytes()); EXPECT_FALSE(writer.xc().Ok()); } TEST(OrConditional, FirstFalse) { ::std::uint8_t buffer[3] = {1, 5}; auto writer = OrConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(3U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(OrConditional, SecondFalse) { ::std::uint8_t buffer[3] = {5, 1}; auto writer = OrConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(3U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(OrConditional, BothTrue) { ::std::uint8_t buffer[3] = {5, 5}; auto writer = OrConditionWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); ASSERT_TRUE(writer.SizeIsKnown()); EXPECT_EQ(3U, writer.SizeInBytes()); EXPECT_TRUE(writer.xc().Ok()); } TEST(ChoiceConditional, UseX) { ::std::array buffer = {1, 5, 0, 10}; auto view = MakeChoiceConditionView(&buffer); EXPECT_TRUE(view.Ok()); EXPECT_TRUE(view.SizeIsKnown()); EXPECT_EQ(4U, view.SizeInBytes()); EXPECT_TRUE(view.has_xyc().ValueOr(false)); EXPECT_EQ(10, view.xyc().Read()); } TEST(ChoiceConditional, UseY) { ::std::array buffer = {2, 5, 0, 10}; auto view = MakeChoiceConditionView(&buffer); EXPECT_TRUE(view.Ok()); EXPECT_TRUE(view.SizeIsKnown()); EXPECT_EQ(3U, view.SizeInBytes()); EXPECT_FALSE(view.has_xyc().ValueOr(true)); } TEST(FlagConditional, True) { ::std::uint8_t buffer[2] = {0x80, 0xff}; auto writer = ContainsContainsBitsWriter(buffer, sizeof buffer); EXPECT_TRUE(writer.Ok()); EXPECT_TRUE(writer.SizeIsKnown()); EXPECT_TRUE(writer.top().Ok()); } TEST(WriteToString, MissingFieldsAreNotWritten) { ::std::uint8_t buffer[2] = {0x01, 0x00}; auto reader = BasicConditionalWriter(buffer, 1U); EXPECT_EQ( "{\n" " x: 1 # 0x1\n" "}", ::emboss::WriteToString(reader, ::emboss::MultilineText())); EXPECT_EQ("{ x: 1 }", ::emboss::WriteToString(reader)); } TEST(WriteToString, NotOkFieldsAreNotWritten) { ::std::uint8_t buffer[2] = {0x00, 0x00}; auto reader = BasicConditionalWriter(buffer, 1U); EXPECT_FALSE(reader.Ok()); EXPECT_EQ( "{\n" " x: 0 # 0x0\n" " # xc: UNREADABLE\n" "}", ::emboss::WriteToString( reader, ::emboss::MultilineText().WithAllowPartialOutput(true))); EXPECT_EQ( "{ x: 0 }", ::emboss::WriteToString( reader, ::emboss::TextOutputOptions().WithAllowPartialOutput(true))); } TEST(WriteToString, NotOkStructSubFieldsAreNotWritten) { ::std::uint8_t buffer[2] = {0x00, 0x00}; auto reader = ConditionalInlineWriter(buffer, 2U); EXPECT_FALSE(reader.Ok()); EXPECT_EQ( "{\n" " payload_id: 0 # 0x0\n" " type_0: {\n" " a: 0 # 0x0\n" " # b: UNREADABLE\n" " # c: UNREADABLE\n" " }\n" "}", ::emboss::WriteToString( reader, ::emboss::MultilineText().WithAllowPartialOutput(true))); EXPECT_EQ( "{ payload_id: 0, type_0: { a: 0 } }", ::emboss::WriteToString( reader, ::emboss::TextOutputOptions().WithAllowPartialOutput(true))); } TEST(WriteToString, PresentFieldsNotWritten) { ::std::uint8_t buffer[2] = {0x00, 0x01}; auto reader = BasicConditionalWriter(buffer, 2U); EXPECT_EQ( "{\n" " x: 0 # 0x0\n" " xc: 1 # 0x1\n" "}", ::emboss::WriteToString(reader, ::emboss::MultilineText())); EXPECT_EQ("{ x: 0, xc: 1 }", ::emboss::WriteToString(reader)); } TEST(WriteToString, AlwaysFalseCondition) { ::std::uint8_t buffer[2] = {0x00}; auto reader = MakeAlwaysFalseConditionView(buffer, 1U); EXPECT_EQ( "{\n" " x: 0 # 0x0\n" "}", ::emboss::WriteToString(reader, ::emboss::MultilineText())); EXPECT_EQ("{ x: 0 }", ::emboss::WriteToString(reader)); } TEST(WriteToString, OnlyAlwaysFalseCondition) { ::std::uint8_t buffer[2] = {0x00}; auto reader = MakeOnlyAlwaysFalseConditionView(buffer, 0U); EXPECT_EQ( "{\n" "}", ::emboss::WriteToString(reader, ::emboss::MultilineText())); EXPECT_EQ("{ }", ::emboss::WriteToString(reader)); } TEST(WriteToString, EmptyStruct) { ::std::uint8_t buffer[2] = {0x00}; auto reader = MakeEmptyStructView(buffer, 0U); EXPECT_EQ( "{\n" "}", ::emboss::WriteToString(reader, ::emboss::MultilineText())); EXPECT_EQ("{ }", ::emboss::WriteToString(reader)); } TEST(ConditionalInline, ConditionalInline) { ::std::uint8_t buffer[4] = {0x00, 0x01, 0x02, 0x03}; auto reader = ConditionalInlineWriter(buffer, 4U); EXPECT_EQ(1, reader.type_0().a().Read()); EXPECT_TRUE(reader.has_type_1().Known()); EXPECT_FALSE(reader.has_type_1().Value()); } TEST(ConditionalAnonymous, ConditionalAnonymous) { ::std::array buffer = {0x00, 0x98}; auto view = MakeConditionalAnonymousView(&buffer); EXPECT_TRUE(view.Ok()); EXPECT_FALSE(view.has_low().Value()); EXPECT_FALSE(view.has_mid().Value()); EXPECT_FALSE(view.has_high().Value()); view.x().Write(100); EXPECT_TRUE(view.has_low().Value()); EXPECT_FALSE(view.has_mid().Value()); EXPECT_TRUE(view.has_high().Value()); EXPECT_EQ(0, view.low().Read()); EXPECT_EQ(1, view.high().Read()); view.low().Write(1); EXPECT_TRUE(view.has_low().Value()); EXPECT_TRUE(view.has_mid().Value()); EXPECT_TRUE(view.has_high().Value()); EXPECT_EQ(1, view.low().Read()); EXPECT_EQ(3, view.mid().Read()); EXPECT_EQ(1, view.high().Read()); } TEST(ConditionalOnFlag, ConditionalOnFlag) { ::std::array buffer = {0x00, 0x98}; auto view = MakeConditionalOnFlagView(&buffer); EXPECT_TRUE(view.Ok()); EXPECT_FALSE(view.enabled().Read()); EXPECT_FALSE(view.has_value().Value()); buffer[0] = 1; EXPECT_TRUE(view.enabled().Read()); EXPECT_TRUE(view.has_value().Value()); EXPECT_EQ(0x98, view.value().Read()); } } // namespace } // namespace test } // namespace emboss