internal static void AssertIsUnbounded(PageNumberAndSize unboundedPage) { Assert.IsTrue(unboundedPage.IsUnbounded); Assert.AreEqual(byte.MinValue, unboundedPage.Size); AssertIsFirstPage(unboundedPage); }
/// <summary> /// Initializes a new instance of the <see cref="PagingInfo"/> struct /// upon deserialization of another <see cref="PagingInfo"/> which /// this one replaces, used for lazy initialization by the internal /// <see cref="Calculator"/> property. /// </summary> /// <param name="calculator"> /// A <see cref="PagingInfoCalculator"/> value initialized from /// the <see cref="CurrentPage"/> and <see cref="TotalItems"/> /// values of a <see cref="PagingInfo"/> value to be replaced /// by this new instance. To understand how this works, /// refer to the <see cref="Calculator"/> property. /// </param> private PagingInfo(PagingInfoCalculator calculator) { this.CurrentPage = calculator.CurrentPage; this.TotalItems = calculator.TotalItems; this.calculator = calculator; this.calculateAllPagesAndItemNumbers = calculator.IncludeAllPagesAndItemNumbers; }
internal static void AssertIsFirstPage(PageNumberAndSize firstPage) { Assert.IsTrue(firstPage.HasValue); Assert.GreaterOrEqual(firstPage.Size, byte.MinValue); Assert.AreEqual(PageNumberAndSize.FirstPageNumber, firstPage.Number); Assert.AreEqual(0, firstPage.Index); }
internal static void AssertIsEmpty(PageNumberAndSize emptyPage) { Assert.IsFalse(emptyPage.HasValue); Assert.IsFalse(emptyPage.IsUnbounded); Assert.AreEqual(byte.MinValue, emptyPage.Size); Assert.AreEqual(0, emptyPage.Number); Assert.AreEqual(-1, emptyPage.Index); }
/// <summary> /// Initializes a new instance of the <see cref="PagingInfo"/> struct /// based on a given <see cref="PageNumberAndSize"/> value. /// </summary> /// <param name="requestedPage"> /// The requested page <see cref="PageNumberAndSize.Number"/> /// and <see cref="PageNumberAndSize.Size"/>. /// If <see cref="PageNumberAndSize.Unbounded"/> is sent, /// all of the items are returned on a single page as large /// as the number of <paramref name="totalItems"/>. /// </param> /// <param name="totalItems"> /// The total number of items in the collection to be paged, /// initial value for the immutable <see cref="TotalItems"/> field. /// </param> /// <param name="calculateAllPagesAndItemNumbers"> /// Indicates whether to include a representation of every /// page and its item numbers in the serialized version of /// this <see cref="PagingInfo"/>, as a list of /// <see cref="PageNumberAndItemNumbers"/>, /// for a paging widget which may want to use them. /// </param> public PagingInfo( PageNumberAndSize requestedPage, int totalItems, bool calculateAllPagesAndItemNumbers = DefaultCalculateAllPagesAndItemNumbers) : this(new PagingInfoCalculator(requestedPage, totalItems, calculateAllPagesAndItemNumbers)) { Contract.Requires <ArgumentException>( requestedPage.HasValue, "The current page must have a value. \"Unbounded\" is an acceptable value."); Contract.Requires <ArgumentOutOfRangeException>( totalItems >= 0, "The number of items in the list must not be negative!"); }
public void Deserializes_As_Invalid_From_Negative_Page_Number() { PageNumberAndSize deserializedPage = JsonConvert.DeserializeObject <PageNumberAndSize>( "{\"Number\":-7,\"Size\":10}"); Assert.IsFalse(deserializedPage.HasValue); Assert.IsFalse(deserializedPage.IsUnbounded); }
public void Deserializes_And_Ignores_Inconsistency_From_Excessive_Specification() { PageNumberAndSize page = new PageNumberAndSize(7, 20); PageNumberAndSize deserializedPage = JsonConvert.DeserializeObject <PageNumberAndSize>( "{\"Number\":7,\"Size\":20,\"Index\":1111111,\"IsUnbounded\":true}"); // ,\"HasValue\":false AssertEquality(page, deserializedPage); }
public void Deserializes_From_Minimal_Specification() { PageNumberAndSize page = new PageNumberAndSize(7); PageNumberAndSize deserializedPage = JsonConvert.DeserializeObject <PageNumberAndSize>( "{\"Number\":7,\"Size\":10}"); AssertEquality(page, deserializedPage); }
public void Serializes_All_Properties() { PageNumberAndSize page = new PageNumberAndSize(7, 20); string serializedPage = JsonConvert.SerializeObject(page); Assert.AreEqual( "{\"Number\":7,\"Size\":20,\"Index\":6,\"IsUnbounded\":false}", // ,\"HasValue\":true serializedPage); }
public void ReturnsUnboundedFromUnbounded() { PagingInfo unboundedPagingInfo = new PagingInfo(PageNumberAndSize.Unbounded, 57); PageNumberAndSize newPage = unboundedPagingInfo.TurnToPage(8); Assert.AreEqual(1, newPage.Number); Assert.AreEqual(0, newPage.Size); Assert.IsTrue(newPage.IsUnbounded); }
public void AllowsTurningPastLastPage() { PagingInfo validPagingInfo = new PagingInfo(3, 10, 57); PageNumberAndSize newPage = validPagingInfo.TurnToPage(8); Assert.AreEqual(8, newPage.Number); Assert.AreEqual(10, newPage.Size); Assert.IsFalse(newPage.IsUnbounded); }
public void DefaultCaseReusesSize() { PagingInfo validPagingInfo = new PagingInfo(3, 10, 57); PageNumberAndSize newPage = validPagingInfo.TurnToPage(2); Assert.AreEqual(2, newPage.Number); Assert.AreEqual(10, newPage.Size); Assert.IsFalse(newPage.IsUnbounded); }
internal static void AssertEquality( PageNumberAndSize expected, PageNumberAndSize actual) { Assert.IsTrue(expected == actual); Assert.IsFalse(expected != actual); Assert.IsTrue(expected.Equals(actual)); Assert.AreEqual(expected, actual); Assert.IsTrue(actual == expected); Assert.IsFalse(actual != expected); Assert.IsTrue(actual.Equals(expected)); Assert.AreEqual(actual, expected); Assert.AreEqual(expected.Number, actual.Number); Assert.AreEqual(expected.Size, actual.Size); Assert.AreEqual(expected.Index, actual.Index); Assert.AreEqual(expected.IsUnbounded, actual.IsUnbounded); Assert.AreEqual(expected.HasValue, actual.HasValue); }
/// <summary> /// Initializes a new instance of the <see cref="PagingInfoCalculator"/> struct. /// Invoked by the private <see cref="PagingInfo.Calculator"/> /// property of an owner <see cref="PagingInfo"/> value, /// calculates metadata for paging UI, optionally including /// a list of all pages and item numbers. For effective lazy /// initialization following deserialization from bare essentials. /// </summary> /// <param name="currentPage"> /// The page <see cref="PageNumberAndSize.Number"/> /// and <see cref="PageNumberAndSize.Size"/>. /// If <see cref="PageNumberAndSize.Unbounded"/> is sent, /// all of the items are returned on a single page as large /// as the number of <paramref name="totalItems"/>. /// </param> /// <param name="totalItems"> /// The total number of items in the collection to be paged, /// initial value for the immutable <see cref="TotalItems"/> field. /// </param> /// <param name="includeAllPagesAndItemNumbers"> /// Whether to fill the set of <see cref="AllPages"/> /// including the item numbers on each page, /// which may be useful for some paging UI. /// Relayed back to the <see cref="PagingInfo"/> via the /// <see cref="IncludeAllPagesAndItemNumbers"/> field, /// adds the private <see cref="PagingInfo.AllPages"/> /// property to the serialization output for JSON. /// </param> internal PagingInfoCalculator( PageNumberAndSize currentPage, int totalItems, bool includeAllPagesAndItemNumbers) { Contract.Requires <ArgumentException>( currentPage.HasValue, "The current page must have a value. \"Unbounded\" is an acceptable value."); Contract.Requires <ArgumentOutOfRangeException>( totalItems >= 0, "The number of items in the list must not be negative!"); this.IncludeAllPagesAndItemNumbers = includeAllPagesAndItemNumbers; this.CurrentPage = currentPage; this.TotalItems = totalItems; if (currentPage.IsUnbounded) { // This is the case where all of the items are returned on // the list, and there is just one unbounded page of items. // The total number of items may exceed the maximum allowed // value of a byte, so the "page size" value remains as zero. // Beware of division by zero! // There are no calculations here based on the page size! this.TotalPages = 1; this.CurrentPage = PageNumberAndSize.Unbounded; this.FirstItemNumber = this.TotalItems > 0 ? 1 : 0; this.LastItemNumber = this.TotalItems; this.ItemCount = this.TotalItems; this.IsFirstPage = true; this.IsLastPage = true; this.PreviousPage = PageNumberAndSize.Empty; this.NextPage = PageNumberAndSize.Empty; this.FirstPage = this.CurrentPage; this.LastPage = this.CurrentPage; } else { this.CurrentPage = currentPage; if ((this.TotalItems > 0) && (this.CurrentPage.Size > 0)) { // Calculate the total pages for a fixed page size and at least one result. this.TotalPages = CalculateTotalPages(this.CurrentPage.Size, this.TotalItems); // Handle the situation if someone turns past the last page. if (this.CurrentPage.Number > this.TotalPages) { // Reset the current page to be the number of the last possible page. this.CurrentPage = new PageNumberAndSize(this.TotalPages, this.CurrentPage.Size); } this.LastItemNumber = this.CurrentPage.Number * this.CurrentPage.Size; this.FirstItemNumber = this.LastItemNumber - this.CurrentPage.Size + 1; this.ItemCount = this.LastItemNumber - this.FirstItemNumber + 1; this.IsFirstPage = this.CurrentPage.Number == PageNumberAndSize.FirstPageNumber; this.IsLastPage = this.CurrentPage.Number == this.TotalPages; if (this.IsFirstPage) { this.FirstPage = this.CurrentPage; this.PreviousPage = PageNumberAndSize.Empty; } else { this.FirstPage = new PageNumberAndSize( PageNumberAndSize.FirstPageNumber, this.CurrentPage.Size); this.PreviousPage = new PageNumberAndSize( this.CurrentPage.Number - 1, this.CurrentPage.Size); } if (this.IsLastPage) { this.LastPage = this.CurrentPage; this.NextPage = PageNumberAndSize.Empty; // The number of items shown on the last page // may be smaller than the number of items per page. this.LastItemNumber = this.TotalItems; } else { this.LastPage = new PageNumberAndSize( this.TotalPages, this.CurrentPage.Size); this.NextPage = new PageNumberAndSize( this.CurrentPage.Number + 1, this.CurrentPage.Size); } } else { // This is the case where the count of TotalItems is zero, // so reset the page number back to the first page. this.CurrentPage = new PageNumberAndSize( PageNumberAndSize.FirstPageNumber, this.CurrentPage.Size); // There is just one page of results, with no items. this.TotalPages = 1; this.FirstItemNumber = 0; this.LastItemNumber = 0; this.ItemCount = 0; this.IsFirstPage = true; this.IsLastPage = true; this.PreviousPage = PageNumberAndSize.Empty; this.NextPage = PageNumberAndSize.Empty; this.FirstPage = this.CurrentPage; this.LastPage = this.CurrentPage; } } this.AllPages = this.IncludeAllPagesAndItemNumbers ? AllPagesAndItemNumbers(this.CurrentPage.Size, this.TotalItems, this.TotalPages) : null; }
public void ReturnsEmptyFromEmpty() { PageNumberAndSize newPage = PagingInfo.Empty.TurnToPage(6); PageNumberAndSizeTests.AssertIsEmpty(newPage); }